1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.devacfr.maven.skins.reflow.snippet;
20  
21  import javax.annotation.Nonnull;
22  import javax.annotation.Nullable;
23  
24  import java.util.Map;
25  import java.util.stream.Collectors;
26  
27  import com.google.common.base.MoreObjects;
28  import com.google.common.collect.Maps;
29  import org.devacfr.maven.skins.reflow.snippet.ComponentToken.Type;
30  import org.jsoup.nodes.Attribute;
31  import org.jsoup.nodes.Attributes;
32  import org.jsoup.nodes.Element;
33  import org.jsoup.nodes.Node;
34  import org.jsoup.nodes.TextNode;
35  import org.jsoup.parser.Tag;
36  
37  import static java.util.Objects.requireNonNull;
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  public class Component<T extends Component<T>> {
48  
49      
50      private final Map<String, String> attributes = Maps.newHashMap();
51  
52      
53      private Component<?> parent;
54  
55      
56      private final Components children = new Components();
57  
58      
59      private final Map<String, Components> childrenMap = Maps.newHashMap();
60  
61      
62      private final Node node;
63  
64      
65  
66  
67  
68  
69      public static Component<?> createComponent(@Nonnull final Node node, final Component<?> parent) {
70          return new Component<>(node).withParent(parent).addAttributes(node.attributes());
71      }
72  
73      
74  
75  
76      protected Component(@Nonnull final Node node) {
77          this.node = requireNonNull(node);
78      }
79  
80      
81  
82  
83      public String getName() {
84          return node.nodeName();
85      }
86  
87      
88  
89  
90      @Nonnull
91      Type getInternalType() {
92          return getRootParent().getType();
93      }
94  
95      
96  
97  
98      public boolean isHtmlTag() {
99          return node instanceof TextNode || Tag.isKnownTag(node.nodeName());
100     }
101 
102     
103 
104 
105     public String getHtml() {
106         if (!isHtmlTag()) {
107             if (children.isEmpty()) {
108                 return null;
109             } else {
110                 return children.html();
111             }
112         } else {
113             return this.node.outerHtml();
114         }
115     }
116 
117     
118 
119 
120     public String getOwnHtml() {
121         if (!isHtmlTag()) {
122             return null;
123         } else {
124             return this.node.outerHtml();
125         }
126     }
127 
128     
129 
130 
131     public Component<?> getParent() {
132         return parent;
133     }
134 
135     @Nullable protected Element getElement() {
136         if (this.node instanceof Element) {
137             return (Element) this.node;
138         }
139         return null;
140     }
141 
142     
143 
144 
145 
146     public Object get(@Nonnull final String name) {
147         requireNonNull(name);
148         String key = name.toLowerCase();
149         
150         if (this.attributes.containsKey(key)) {
151             return this.attributes.get(key);
152         } else {
153             
154             
155             if (key.endsWith("s") && !this.childrenMap.containsKey(key)) {
156                 key = key.substring(0, key.length() - 1);
157                 if (this.childrenMap.containsKey(key)) {
158                     return this.childrenMap.get(key);
159                 }
160             } else if (this.childrenMap.containsKey(key)) {
161                 final Components value = this.childrenMap.get(key);
162                 
163                 if (value.size() > 1) {
164                     return value;
165                 }
166                 return value.first();
167             }
168         }
169         return null;
170     }
171 
172     public Map<String, String> getAttrs() {
173         return this.attributes;
174     }
175 
176     
177 
178 
179     public Components getChildren() {
180         return children;
181     }
182 
183     public Components getChildren(final String name) {
184         final String key = requireNonNull(name).toLowerCase();
185         if (this.childrenMap.containsKey(key)) {
186             return this.childrenMap.get(key);
187         }
188         return Components.empty();
189     }
190 
191     public T addChild(final Component<?> component) {
192         final String key = component.getName();
193         Components value = null;
194         if (!this.childrenMap.containsKey(key)) {
195             value = new Components();
196             this.childrenMap.put(key, value);
197         } else {
198             value = this.childrenMap.get(key);
199         }
200         value.add(component);
201         this.children.add(component);
202         return self();
203     }
204 
205     protected T withParent(final Component<?> parent) {
206         this.parent = parent;
207         return self();
208     }
209 
210     @Nonnull
211     protected SnippetComponent<?> getRootParent() {
212         Component<?> parent = this.parent;
213         while (!(parent instanceof SnippetComponent<?>)) {
214             parent = parent.parent;
215         }
216         return (SnippetComponent<?>) parent;
217     }
218 
219     
220 
221 
222 
223     protected T addAttributes(@Nonnull final Attributes attrs) {
224         attrs.asList().stream().forEach(this::addAttribute);
225         return self();
226     }
227 
228     
229 
230 
231 
232     protected T addAttribute(@Nonnull final Attribute attr) {
233         this.attributes.put(requireNonNull(attr.getKey()).toLowerCase(), requireNonNull(attr.getValue()));
234         return self();
235     }
236 
237     
238 
239 
240     @SuppressWarnings("unchecked")
241     protected T self() {
242         return (T) this;
243     }
244 
245     
246 
247 
248     @Override
249     public String toString() {
250         return MoreObjects.toStringHelper(this)
251                 .add("name", this.getName())
252                 .add("isHtmlTag", this.isHtmlTag())
253                 .add("attributes", this.attributes)
254                 .add("children", this.children.stream().map((cpt) -> cpt.getName()).collect(Collectors.toList()))
255                 .toString();
256     }
257 }