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 CLASS=JDDescLabel>Trade Off:</B>
031     * 
032     * <BR />If the programmer or user ever wishes to perform a search, it becomes obvious that
033     * leaving off the beginning and trailing {@code '<!--'} and {@code '-->'} markers when
034     * specifying a search provides more easily readable code, and less error prone code.  Thus,
035     * when using the {@code CommentNodeFind, Get, Peek, Poll, etc...} methods in the
036     * {@code package NodeSearch}, a Java String {@code substring(...)} would have to be invoked
037     * on every search comparison loop invocation.  Primarily, keeping {@code class HTMLNode} and
038     * it's descendants all immutable is a much higher priority to ensure clean code, it becomes
039     * necessary to keep a redundant copy of the body {@code String}.
040     */
041    public final String body;
042
043    /**
044     * This constructor simply makes a call to {@code super(s); } <I>a.k.a.</I>
045     * {@code class HTML.HTMLNode}
046     * 
047     * <BR /><BR />This constructor also checks to ensure that the internal {@code String}-field
048     * ({@code public final String str}) contains beginning and ending comment markers:
049     * {@code '<!--'} and {@code '-->'}
050     *  
051     * @throws IllegalArgumentException If the passed string does not start and end with the
052     * appropriate HTML comment-markers: {@code <!--} and {@code -->}
053     */
054    public CommentNode(String s)
055    {
056        super(s);
057
058        if (! s.startsWith("<!--")) throw new IllegalArgumentException
059            ("The passed HTML string does not start with comment marker '<!--'");
060
061        if (! s.endsWith("-->"))    throw new IllegalArgumentException
062            ("The passed HTML string does not end with comment marker '-->'");
063
064        body = str.substring(4, str.length() - 3);
065
066        if (body.contains("-->"))   throw new IllegalArgumentException
067            ("The passed HTML string has multiple occurrences of substring '-->'");
068    }
069
070    /**
071     * This method identifies that {@code 'this'} instance of (abstract parent-class)
072     * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}.
073     *
074     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
075     * 
076     * <BR />This method is final, and cannot be modified by sub-classes.
077     * 
078     * @return This method shall always return {@code TRUE}  It overrides the parent-class
079     * {@code HTMLNode} method {@link #isCommentNode()}, which always returns {@code FALSE}.
080     */
081    @Override
082    public final boolean isCommentNode() { return true; }
083
084    /**
085     * This method identifies that {@code 'this'} instance of (abstract parent-class)
086     * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}.
087     * 
088     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
089     * 
090     * <BR />This method is final, and cannot be modified by sub-classes.
091     * 
092     * @return {@code 'this'} reference.  This method can be used inside loops for improving
093     * the readability of loop-condition expressions.  See example below:
094     * 
095     * <DIV CLASS=EXAMPLE>{@code
096     * Vector<HTMLNode> fileVec = HTMLPage.getPageTokens(new URL("http://some.url.com"), false);
097     * CommentNode c;
098     * 
099     * // NOTE: The casting to class CommentNode is automatically acheived with this method,
100     * //       which can make loops a lot easier to read.  Only a CommentNode instance will have 
101     * //       a '.body' field.  Attempting to read a '.body' field from an instance of HTMLNode
102     * //       would immediately generate a compile-time error.
103     * 
104     * for (HTMLNode n : fileVec)
105     *     if ((c = myHTMLVector.elementAt(i).ifCommentNode()) != null)
106     *         if (c.body.equals("Some Comment Node Text"))
107     *             ...
108     * }</div>
109     * 
110     * <BR /><BR />This method-version overrides the parent-class-version, which always returns
111     * null.  This method is <I>not overriden by other {@code HTMLNode} sub-classes.</I>
112     */
113    @Override
114    public final CommentNode ifCommentNode() { return this; }
115
116    /**
117     * Java's {@code interface Cloneable} requirements.  This instantiates a new
118     * {@code CommentNode} with identical {@code String str} and {@code String body} fields.
119     * @return A new {@code CommentNode} whose internal fields are identical to this one.
120     */
121    public CommentNode clone() { return new CommentNode(str); }
122
123    /**
124     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
125     * using the underlying field {@code final String str} that all {@code HTMLNode's} contain.
126     * @param cn Any other {@code CommentNode} to be compared to {@code 'this' CommentNode}
127     * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean
128     * compareTo(T t)} method requirements.
129     */
130    public int compareTo(CommentNode cn)
131    { return this.body.compareToIgnoreCase(cn.body); }
132}