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