001package Torello.HTML;
002
003/**
004 * Represents HTML Comments, and is one of only three HTML Element Classes provided by the Java
005 * HTML Library Tool, and also one of the three data-classes that can be generated by the HTML
006 * Parser.
007 * 
008 * <EMBED CLASS='external-html' DATA-FILE-ID=COMMENT_NODE>
009 * 
010 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_NODE_SUB_IMG>
011 * 
012 * @see TagNode
013 * @see TextNode
014 * @see HTMLNode
015 */
016@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="HTML_NODE_SUBCLASS")
017public final class CommentNode
018    extends HTMLNode 
019    implements CharSequence, java.io.Serializable, Cloneable, Comparable<CommentNode>
020{
021    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
022    public static final long serialVersionUID = 1;
023
024    /**
025     * This stores a copy of the body of the comment.  Specifically, (and simply) the java string
026     * method {@code body = str.substring(4, str.length() - 3);} is called and stored here.  Yes,
027     * this does mean that extra memory / double memory is used to store comments, however the 
028     * trade-offs are somewhat high.
029     *
030     * <BR /><BR /><B><SPAN STYLE="color: red;">TRADEOFFS:</B></SPAN> If the programmer or user
031     * ever wishes to perform a search, it becomes obvious that leaving off the beginning and
032     * trailing {@code '<!--'} and {@code '-->'} markers when specifying a search provides more
033     * easily readable code, and less error prone code.  Thus, when using the
034     * {@code CommentNodeFind, Get, Peek, Poll, etc...} methods in the {@code package NodeSearch},
035     * a Java String {@code substring(...)} would have to be invoked on every search comparison 
036     * loop invocation.  Primarily, keeping {@code class HTMLNode} and it's descendants all
037     * immutable is a much higher priority to ensure clean code, it becomes necessary to keep a
038     * redundant copy of the body {@code String}.
039     */
040    public final String body;
041
042    /**
043     * This constructor simply makes a call to {@code super(s); } <I>a.k.a.</I>
044     * {@code class HTML.HTMLNode}
045     * 
046     * <BR /><BR />This constructor also checks to ensure that the internal {@code String}-field
047     * ({@code public final String str}) contains beginning and ending comment markers:
048     * {@code '<!--'} and {@code '-->'}
049     *  
050     * @throws IllegalArgumentException If the passed string does not start and end with the
051     * appropriate HTML comment-markers: {@code <!--} and {@code -->}
052     */
053    public CommentNode(String s)
054    {
055        super(s);
056
057        if (! s.startsWith("<!--")) throw new IllegalArgumentException
058            ("The passed HTML string does not start with comment marker '<!--'");
059
060        if (! s.endsWith("-->"))    throw new IllegalArgumentException
061            ("The passed HTML string does not end with comment marker '-->'");
062
063        body = str.substring(4, str.length() - 3);
064
065        if (body.contains("-->"))   throw new IllegalArgumentException
066            ("The passed HTML string has multiple occurrences of substring '-->'");
067    }
068
069    /**
070     * This method identifies that {@code 'this'} instance of (abstract parent-class)
071     * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}.
072     *
073     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
074     * 
075     * <BR />This method is final, and cannot be modified by sub-classes.
076     * 
077     * @return This method shall always return {@code TRUE}  It overrides the parent-class
078     * {@code HTMLNode} method {@link #isCommentNode()}, which always returns {@code FALSE}.
079     */
080    @Override
081    public final boolean isCommentNode() { return true; }
082
083    /**
084     * This method identifies that {@code 'this'} instance of (abstract parent-class)
085     * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}.
086     * 
087     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
088     * 
089     * <BR />This method is final, and cannot be modified by sub-classes.
090     * 
091     * @return {@code 'this'} reference.  This method can be used inside loops for improving
092     * the readability of loop-condition expressions.  See example below:
093     * 
094     * <DIV CLASS=EXAMPLE>{@code
095     * Vector<HTMLNode> fileVec = HTMLPage.getPageTokens(new URL("http://some.url.com"), false);
096     * CommentNode c;
097     * 
098     * // NOTE: The casting to class CommentNode is automatically acheived with this method,
099     * //       which can make loops a lot easier to read.  Only a CommentNode instance will have 
100     * //       a '.body' field.  Attempting to read a '.body' field from an instance of HTMLNode
101     * //       would immediately generate a compile-time error.
102     * 
103     * for (HTMLNode n : fileVec)
104     *     if ((c = myHTMLVector.elementAt(i).ifCommentNode()) != null)
105     *         if (c.body.equals("Some Comment Node Text"))
106     *             ...
107     * }</div>
108     * 
109     * <BR /><BR />This method-version overrides the parent-class-version, which always returns
110     * null.  This method is <I>not overriden by other {@code HTMLNode} sub-classes.</I>
111     */
112    @Override
113    public final CommentNode ifCommentNode() { return this; }
114
115    /**
116     * Java's {@code interface Cloneable} requirements.  This instantiates a new
117     * {@code CommentNode} with identical {@code String str} and {@code String body} fields.
118     * @return A new {@code CommentNode} whose internal fields are identical to this one.
119     */
120    public CommentNode clone() { return new CommentNode(str); }
121
122    /**
123     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
124     * using the underlying field {@code final String str} that all {@code HTMLNode's} contain.
125     * @param cn Any other {@code CommentNode} to be compared to {@code 'this' CommentNode}
126     * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean
127     * compareTo(T t)} method requirements.
128     */
129    public int compareTo(CommentNode cn)
130    { return this.body.compareToIgnoreCase(cn.body); }
131}