001package Torello.HTML;
002
003import Torello.JavaDoc.JDHeaderBackgroundImg;
004
005/**
006 * This class is mostly a wrapper for class <CODE>java&#46;lang&#46;String</CODE>, and serves as
007 * the abstract parent of the three types of HTML elements offered by the Java HTML Library.
008 * 
009 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_NODE>
010 * 
011 * @see TagNode
012 * @see TextNode
013 * @see CommentNode
014 */
015@JDHeaderBackgroundImg(EmbedTagFileID={"HTML_NODE_HEADER", "HTML_NODE_SUB_IMG"})
016public abstract class HTMLNode implements CharSequence, java.io.Serializable, Cloneable
017{
018    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
019    public static final long serialVersionUID = 1;
020
021    /**
022     * This is an immutable field.  It stores the complete contents of an HTML node.  It can be 
023     * either the <B>"textual contents"</B>
024     * of an HTML {@code TagNode}, or the text (directly) of the text-inside of an HTML page!
025     * 
026     * <BR /><BR />
027     * <B>FOR INSTANCE:</B>
028     * 
029     * <BR /><BR /><UL CLASS=JDUL>
030     * <LI>A subclass of HTMLNode - <CODE>TagNode</CODE> - could contain the String
031     *      <SPAN STYLE="color: red;">&lt;SPAN STYLE="CSS INFO"&gt;"</SPAN>
032     *      <I>inside this <CODE><B>str field</CODE></B> here.</I>
033     * </LI>
034     * <LI> The other sub-class of HTML - <CODE>TextNode</CODE> - could contain the {@code String}
035     *      <SPAN STYLE="color: red;">"This is a news-page from www.Gov.CN Chinese Government
036     *      Portal."</SPAN> <I>inside this <CODE><B>str field</CODE></B> here.</I>
037     * </LI>
038     * </UL>
039     * 
040     * <BR /><B>NOTE:</B> Because sub-classes of {@code HTMLNode} are all immutable, generally,
041     * if you wish to change the contents of an HTML page, a programmer is required to create new
042     * nodes, rather than changing these fields.
043     */
044    public final String str;
045
046    /**
047     * Constructor that builds a new {@code HTMLNode}
048     * 
049     * @param s A valid string of an HTML element.
050     */
051    protected HTMLNode(String s)
052    { this.str = s; }
053
054    /**
055     * Java's hash-code requirement.
056     * 
057     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
058     * 
059     * <BR />This method is final, and cannot be modified by sub-classes.
060     * 
061     * @return A hash-code that may be used when storing this node in a java sorted-collection.
062     */
063    public final int hashCode()
064    { return this.str.hashCode(); }
065
066    /**
067     * Java's {@code public boolean equals(Object o)} requirements.
068     * 
069     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
070     * 
071     * <BR />This method is final, and cannot be modified by sub-classes.
072     * 
073     * @param o This may be any Java Object, but only ones of {@code 'this'} type whose
074     * internal-values are identical will cause this method to return {@code TRUE}.
075     * 
076     * @return {@code TRUE} If {@code 'this'} equals another object {@code HTMLNode.}
077     */
078    public final boolean equals(Object o)
079    {
080        if (o == null) return false;
081        if (o == this) return true;
082
083        if (! this.getClass().equals(o.getClass())) return false;
084
085        return ((HTMLNode) o).str.equals(this.str);
086    }
087
088    /**
089     * Sub-classes of {@code HTMLNode} must be {@code Cloneable.}
090     * 
091     * @return Must return an identical copy of {@code 'this'} node.  The object reference cannot
092     * be {@code 'this'} reference.
093     */
094    public abstract HTMLNode clone();
095
096
097    // **********************************************************************************************
098    // CharSequence Methods
099    // **********************************************************************************************
100
101    /**
102     * Java's {@code toString()} requirement.
103     * 
104     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
105     * 
106     * <BR />This method is final, and cannot be modified by sub-classes.
107     * 
108     * @return A {@code String}-representation of this {@code HTMLNode.}
109     */
110    public final String toString() { return this.str; }
111
112    /**
113     * Returns the char value at the specified index of the field: {@code public final String str}.
114     * An index ranges from {@code '0'} (zero) to {@code HTMLNode.str.length() - 1.} The first 
115     * {@code char} value of the sequence is at index zero, the next at index one, and so on, as 
116     * for array indexing.
117     * 
118     * <BR /><BR /><B>NOTE:</B> If the {@code char} value specified by the index is a surrogate, 
119     * the surrogate value is returned.
120     * 
121     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
122     * 
123     * <BR />This method is final, and cannot be modified by sub-classes.
124     * 
125     * @param index The index of the {@code char} value to be returned
126     * 
127     * @return The specified {@code char} value
128     */
129    public final char charAt(int index) { return str.charAt(index); }
130
131    /**
132     * Returns the length of the field {@code public final String str}. 
133     * The length is the number of 16-bit chars in the sequence.
134     * 
135     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
136     * 
137     * <BR />This method is final, and cannot be modified by sub-classes.
138     * 
139     * @return the number of {@code chars} in {@code this.str}
140     */
141    public final int length() { return str.length(); }
142
143    /**
144     * Returns a {@code CharSequence} that is a subsequence of the {@code public final String str}
145     * field of {@code 'this' HTMLNode}.
146     * The subsequence starts with the {@code char} value at the specified index and ends with the 
147     * {@code char} value at index {@code end - 1.} The length (in chars) of the returned sequence
148     * is {@code end - start},  so if {@code start == end} then an empty sequence is returned.
149     * 
150     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
151     * 
152     * <BR />This method is final, and cannot be modified by sub-classes.
153     * 
154     * @param start The start index, inclusive
155     * @param end The end index, exclusive
156     * 
157     * @return The specified subsequence
158     */
159    public final CharSequence subSequence(int start, int end)
160    { return str.substring(start, end); }
161
162
163    // ********************************************************************************************
164    // ********************************************************************************************
165    // 'is' Optimization Methods
166    // ********************************************************************************************
167    // ********************************************************************************************
168
169
170    /**
171     * This method will return {@code TRUE} for any instance of {@code 'CommentNode'}.
172     *
173     * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever
174     * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited
175     * instance of {@code CommentNode}.  This is (marginally) more efficient than using the Java
176     * {@code 'instanceof'} operator.
177     *
178     * @return This (top-level inheritance-tree) method always returns {@code FALSE}.  The 
179     * {@code '.java'} file for {@code class CommentNode} overrides this method, and returns
180     * {@code TRUE}.
181     * 
182     * @see CommentNode#isCommentNode()
183     */
184    public boolean isCommentNode()
185    {
186        // This method will *only* be over-ridden by subclass CommentNode, where it shall return
187        // TRUE.  Neither class TextNode, nor class TagNode will over-ride this method.
188
189        return false;
190    }
191
192    /**
193     * This method will return {@code TRUE} for any instance of {@code 'TextNode'}.
194     *
195     * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever
196     * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited
197     * instance of {@code TextNode}.  This is (marginally) more efficient than using the Java
198     * {@code 'instanceof'} operator.
199     *
200     * @return This (top-level inheritance-tree) method always returns {@code FALSE}.  The 
201     * {@code '.java'} file for {@code class TextNode} overrides this method, and returns
202     * {@code TRUE}.
203     * 
204     * @see TextNode#isTextNode()
205     */
206    public boolean isTextNode()
207    {
208        // This method will *only* be over-ridden by subclass CommentNode, where it shall return
209        // TRUE.  Neither class TextNode, nor class TagNode will over-ride this method.
210
211        return false;
212    }
213
214    /**
215     * This method will return {@code TRUE} for any instance of {@code 'TagNode'}.
216     *
217     * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever
218     * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited
219     * instance of {@code TagNode}.  This is (marginally) more efficient than using the Java
220     * {@code 'instanceof'} operator.
221     *
222     * @return This (top-level inheritance-tree) method always returns {@code FALSE}.  The 
223     * {@code '.java'} file for {@code class TagNode} overrides this method, and returns
224     * {@code TRUE}.
225     * 
226     * @see TagNode#isTagNode()
227     */
228    public boolean isTagNode()
229    {
230        // This method will *only* be over-ridden by subclass TagNode, where it shall return
231        // TRUE.  Neither class TextNode, nor class CommentNode will over-ride this method.
232
233        return false;
234    }
235
236
237    // ********************************************************************************************
238    // ********************************************************************************************
239    // TagNode Optimization Methods
240    // ********************************************************************************************
241    // ********************************************************************************************
242
243
244    /**
245     * <EMBED CLASS='external-html' DATA-RET=null DATA-FILE-ID=OPEN_TAG_PWA_DESC>
246     * 
247     * <BR /><BR />This makes the process of finding {@code TagNode's} having a particular
248     * attribute much more efficient.
249     *
250     * <BR /><BR />The purpose of this method is to quickly return a node that has been cast to
251     * an instance of {@code TagNode}, if it is, indeed, a {@code TagNode} <B><I>and if</I></B> it
252     * has an internal-{@code String} long-enough to possibly contain attributes (inner-tags).
253     * 
254     * @return This method shall always return null, unless this method has been overridden by a
255     * sub-class.  Only {@code TagNode} overrides this method, and this method will return
256     * {@code 'this'} instance, if and only if the following conditions hold:
257     * 
258     * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET>
259     * 
260     * @see TagNode#openTagPWA()
261     * @see isOpenTagPWA()
262     */
263    public TagNode openTagPWA()
264    {
265        // This method will *only* be over-ridden by subclass TagNode.
266        // For instances of inheriting class TextNode and CommentNode, this always returns null.
267        // In 'TagNode' this method returns true based on the 'isClosing' field from that class,
268        // and the length of the 'str' field from this class.
269
270        return null;
271    }
272
273    /**
274     * <EMBED CLASS='external-html' DATA-RET=null DATA-FILE-ID=OPEN_TAG_DESC>
275     *
276     * @return This method shall always return null, unless this method has been overridden by a
277     * sub-class.  Only {@code TagNode} overrides this method, and this method will return
278     * {@code 'this'} instance, if and only if the following conditions hold:
279     * 
280     * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET>
281     * 
282     * <BR /><BR />When the overridden {@code TagNode} sub-class returns a non-null result, that
283     * value will <B>always be equal to {@code 'this'}</B>
284     * 
285     * @see TagNode#openTag()
286     */
287    public TagNode openTag()
288    {
289        // This method will *only* be over-ridden by subclass TagNode.
290        // For instances of inheriting class TextNode and CommentNode, this always returns null.
291        // In 'TagNode' this method returns true based on that class 'isClosing' field.
292
293        return null;
294    }
295
296
297    // ********************************************************************************************
298    // ********************************************************************************************
299    // TagNode Optimization Methods, Part II - Same as above, but returns boolean
300    // ********************************************************************************************
301    // ********************************************************************************************
302
303
304    /**
305     * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=OPEN_TAG_PWA_DESC>
306     * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=IS_OPEN_TAG_PWA_EX>
307     * 
308     * @return This method shall always return {@code FALSE}, unless it has been overriden by a
309     * subclass.  Subclass {@link TagNode} overrides this, and will return {@code TRUE} if and only
310     * if the following conditions hold:
311     * 
312     * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET>
313     * 
314     * @see TagNode#isOpenTagPWA()
315     * @see #openTagPWA()
316     */
317    public boolean isOpenTagPWA()
318    {
319        // This method will *only* be over-ridden by subclass TagNode.
320        // For instances of inheriting class TextNode and CommentNode, this always returns false.
321        // In 'TagNode' this method returns TRUE based on the 'isClosing' field from that class,
322        // and the length of the 'str' field from this class.
323
324        return false;
325    }
326
327    /**
328     * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=OPEN_TAG_DESC>
329     *
330     * <BR /><BR />This method will function almost identically to {@link #openTag()}, with the
331     * subtle difference being that it returns a {@code TRUE / FALSE} boolean, instead of an
332     * instance-reference.
333     * 
334     * @return This method shall always return {@code FALSE}, unless it has been overriden by a
335     * subclass.  Subclass {@link TagNode} overrides this, and will return {@code TRUE} if and only
336     * if the following conditions hold:
337     * 
338     * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_RET>
339     * 
340     * @see TagNode#isOpenTag()
341     * @see #openTag()
342     */
343    public boolean isOpenTag()
344    {
345        // This method will *only* be over-ridden by subclass TagNode.
346        // For instances of inheriting class TextNode and CommentNode, this always returns FALSE.
347        // In 'TagNode' this method returns TRUE based on that class 'isClosing' field.
348
349        return false;
350    }
351
352
353    // ********************************************************************************************
354    // ********************************************************************************************
355    // 'if' loop-optimizers
356    // ********************************************************************************************
357    // ********************************************************************************************
358
359
360    /**
361     * <B STYLE='color: red;'>Loop Optimization Method</B>
362     * 
363     * <BR /><BR />When this method is invoked on an instance of sub-class {@link TagNode},
364     * this method produces {@code 'this'} instance.
365     * 
366     * @return This method is overriden by sub-class {@code TagNode}, and in that class, this
367     * method simply returns {@code 'this'}.  The other sub-classes of this ({@code abstract})
368     * class inherit this version of this method, and therefore return null.
369     * 
370     * @see TagNode#ifTagNode()
371     */
372    public TagNode ifTagNode()
373    {
374        // This method will *only* be over-ridden by subclass TagNode, where it shall return
375        // 'this'.  Neither class TextNode, nor class CommentNode will over-ride this method.
376
377        return null;
378    }
379
380    /**
381     * <B STYLE='color: red;'>Loop Optimization Method</B>
382     * 
383     * <BR /><BR />When this method is invoked on an instance of sub-class {@link TextNode},
384     * this method produces {@code 'this'} instance.
385     * 
386     * @return This method is overriden by sub-class {@code TextNode}, and in that class, this
387     * method simply returns {@code 'this'}.  The other sub-classes of this ({@code abstract})
388     * class inherit this version of this method, and therefore return null.
389     * 
390     * @see TextNode#ifTextNode()
391     */
392    public TextNode ifTextNode()
393    {
394        // This method will *only* be over-ridden by subclass TextNode, where it shall return
395        // 'this'.  Neither class TagNode, nor class CommentNode will over-ride this method.
396
397        return null;
398    }
399
400    /**
401     * <B STYLE='color: red;'>Loop Optimization Method</B>
402     * 
403     * <BR /><BR />When this method is invoked on an instance of sub-class {@link CommentNode},
404     * this method produces {@code 'this'} instance.
405     * 
406     * @return This method is overriden by sub-class {@code CommentNode}, and in that class, this
407     * method simply returns {@code 'this'}.  The other sub-classes of this ({@code abstract})
408     * class inherit this version of this method, and therefore return null.
409     * 
410     * @see CommentNode#ifCommentNode()
411     */
412    public CommentNode ifCommentNode()
413    {
414        // This method will *only* be over-ridden by subclass CommentNode, where it shall return
415        // 'this'.  Neither class TagNode, nor class TextNode will over-ride this method.
416
417        return null;
418    }
419
420
421    // ********************************************************************************************
422    // ********************************************************************************************
423    // 'is' loop-optimizers
424    // ********************************************************************************************
425    // ********************************************************************************************
426
427
428    /**
429     * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code TagNode}.
430     * 
431     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
432     * 
433     * <BR />This method is final, and cannot be modified by sub-classes.
434     * 
435     * @return Simply returns {@code 'this'} instance.  (Note that the method
436     * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the
437     * compile-time logic some 'proof' in its type-analysis)
438     * 
439     * @throws ClassCastException <B STYLE='color: red;'>IMPORTANT:</B> If the instance is a
440     * {@link TextNode} or {@code CommentNode}, rather than a {@link TagNode}, then (naturally) the
441     * JVM will immediately throw a casting exception.
442     */
443    public final TagNode asTagNode() { return TagNode.class.cast(this); }
444
445    /**
446     * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code TextNode}.
447     * 
448     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
449     * 
450     * <BR />This method is final, and cannot be modified by sub-classes.
451     * 
452     * @return Simply returns {@code 'this'} instance.  (Note that the method
453     * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the
454     * compile-time logic some 'proof' in its type-analysis)
455     * 
456     * @throws ClassCastException <B STYLE='color: red;'>IMPORTANT:</B> If the instance is a
457     * {@link TagNode} or {@code CommentNode}, rather than a {@link TextNode}, then (naturally) the
458     * JVM will immediately throw a casting exception.
459     */
460    public final TextNode asTextNode() { return TextNode.class.cast(this); }
461
462    /**
463     * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code CommentNode}.
464     * 
465     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
466     * 
467     * <BR />This method is final, and cannot be modified by sub-classes.
468     * 
469     * @return Simply returns {@code 'this'} instance.  (Note that the method
470     * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the
471     * compile-time logic some 'proof' in its type-analysis)
472     * 
473     * @throws ClassCastException <B STYLE='color: red;'>IMPORTANT:</B> If the instance is a
474     * {@link TagNode} or {@code TextNode}, rather than a {@link CommentNode}, then (naturally) the
475     * JVM will immediately throw a casting exception.
476     */
477    public final CommentNode asCommentNode() { return CommentNode.class.cast(this); }
478}