001package Torello.HTML;
002
003import java.util.Vector;
004import java.io.Serializable;
005import java.util.Comparator;
006
007/**
008 * The abstract parent class of all three {@code NodeIndex} classes, {@link TagNodeIndex},
009 * {@link TextNodeIndex} and {@link CommentNodeIndex}.
010 * 
011 * <BR /><BR /><EMBED CLASS="external-html" DATA-FILE-ID=NODE_INDEX>
012 * 
013 * @param <NODE> The class of {@code HTMLNode} represented by this {@code NodeIndex} instance.
014 * @see HTMLNode
015 * @see CommentNodeIndex
016 * @see TagNodeIndex
017 * @see TextNodeIndex
018 */
019@SuppressWarnings("rawtypes")
020public abstract class NodeIndex<NODE extends HTMLNode>
021    implements CharSequence, Serializable, Cloneable, Replaceable
022{
023    // ********************************************************************************************
024    // ********************************************************************************************
025    // Fields
026    // ********************************************************************************************
027    // ********************************************************************************************
028
029
030    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUID"> */
031    public static final long serialVersionUID = 1;
032
033    /**
034     * An index to a node from a web-page.   This index must point to a the exact same node inside
035     * of a vectorized-html page as the node stored in member-field {@code HTMLNode 'n'}.  
036     */
037    public final int index;
038
039    /**
040     * A {@code HTMLNode} from a web-page.  This node is supposed to be the same node stored at the
041     * index specified by member-field {@code int 'index'} of some vectorized-html web-page in
042     * memory or on disk.
043     */
044    public NODE n;
045
046
047    // ********************************************************************************************
048    // ********************************************************************************************
049    // Constructor
050    // ********************************************************************************************
051    // ********************************************************************************************
052
053
054    /** 
055     * a default constructor.  This assigns a value to the index field.
056     * 
057     * @param index This is the vector-index location of HTMLNode 'n' inside of a vectorized-HTML
058     * web-page.
059     * 
060     * <BR /><BR /><B><SPAN STYLE="color: red;">STALE DATA NOTE:</B></SPAN> This class is a
061     * minor-use class, not one of the primary data classes.  This instance shall become 'useless'
062     * the moment the vector that was used to instantiate this class is modified, and the node 'n'
063     * is no longer at vector-index 'index.'  These "NodeIndex" classes are retained, not
064     * deprecated due to the fundamental nature of using the classes of the NodeSearch Package.
065     * Data is easily made stale.  Generally, when modifying HTML Vectors, the easiest thing to do
066     * is <I><B>to remember to modify a vector at specific locations by iterating from the end of
067     * the vector, back to the beginning.</I></B>  This will generally prevent "state-data
068     * vector-indexes" from rearing their ugly head.
069     * 
070     * @param n An HTMLNode that needs to be the node found in the underlying vector at
071     * vector-index 'index.'
072     *
073     * @throws IndexOutOfBoundsException if {@code index} is negative, this exception is thrown.
074     * @throws NullPointerException if {@code n} is null.
075     */
076    protected NodeIndex(int index, NODE n)
077    {
078        this.index = index;
079        this.n = n;
080
081        if (n == null)  throw new NullPointerException(
082            "HTMLNode parameter 'n' to this constructor was passed a null value, but this " +
083            "is not allowed here."
084        );
085
086        if (index < 0)  throw new IndexOutOfBoundsException(
087            "Integer parameter 'index' to this constructor was passed a negative value: " +
088            index
089        );
090    }
091
092    /**
093     * Simple dispatch method helper that switches on the class of input parameter {@code 'n'}.
094     * 
095     * @param n Any of the three Java HTML defined {@code HTMLNode} subclasses - {@link TagNode},
096     * {@link TextNode} or {@code CommentNode}
097     * 
098     * @return A {@code NodeIndex} inheriting class that is appropriate to {@code 'n'}.
099     * 
100     * @throws IllegalArgumentException If the user has extended class {@code HTMLNode}, and passed
101     * this unrecognized {@code HTMLNode} Type.
102     */
103    public static final NodeIndex<?> newNodeIndex(int index, HTMLNode n)
104    {
105        Class<?> newNodeClass = n.getClass();
106
107        if (TagNode.class.isAssignableFrom(newNodeClass))
108            return new TagNodeIndex(index, (TagNode) n);
109
110        if (TextNode.class.isAssignableFrom(newNodeClass))
111            return new TextNodeIndex(index, (TextNode) n);
112
113        if (CommentNode.class.isAssignableFrom(newNodeClass))
114            return new CommentNodeIndex(index, (CommentNode) n);
115
116        throw new IllegalArgumentException
117            ("Parameter 'n' has a Type that is an Unrecognized HTMLNode-SubClass Type");
118    }
119
120    // ********************************************************************************************
121    // ********************************************************************************************
122    // java.lang.Object Methods
123    // ********************************************************************************************
124    // ********************************************************************************************
125
126
127    /**
128     * Java's {@code public boolean equals(Object o)} requirements.
129     * 
130     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
131     * cannot be modified by sub-classes.
132     * 
133     * @param o This may be any Java Object, but only ones of {@code 'this'} type whose
134     * internal-values are identical will bring this method to return true.
135     * 
136     * @return <B>TRUE</B> If {@code 'this'} equals another object {@code HTMLNode.}
137     */
138    public final boolean equals(Object o)
139    {
140        NodeIndex<?> other;
141
142        return (    this == o)
143                || (    (o != null)
144                    &&  (this.getClass().equals(o.getClass()))
145                    &&  ((other = (NodeIndex) o).n.str.equals(this.n.str))
146                    &&  (other.index == this.index));
147    }
148
149    /**
150     * Java's hash-code requirement.
151     * 
152     * @return A hash-code that may be used when storing this node in a java hashed-collection.
153     * The {@link #index} of this {@code NodeIndex} ought to be be a unique hash.
154     */
155    public int hashCode() { return index; }
156
157    /**
158     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
159     * using the vector-index position.
160     * 
161     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
162     * cannot be modified by sub-classes.
163     * 
164     * @param ni Any other {@code NodeIndex} to be compared to {@code 'this' NodeIndex}
165     * 
166     * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean
167     * compareTo(T t)} method requirements.
168     * 
169     * @see #index
170     */
171    // @SuppressWarnings("rawtypes")
172    // public final int compareTo(NodeIndex ni)
173    // { return this.index - ni.index; }
174
175    /**
176     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
177     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
178     * JDK package {@code java.util.*;}
179     * 
180     * <BR /><BR /><B>NOTE:</B> This version utilizes the standard JDK
181     * {@code String.compareTo(String)} method.
182     * 
183     * @see HTMLNode#str
184     */
185    public static final Comparator<TextNodeIndex> comp2 =
186        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareTo(txni2.n.str);
187    
188    /**
189     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
190     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
191     * JDK package {@code java.util.*;}
192     * 
193     * <BR /><BR /><B>NOTE:</B> This version utilizes the standard JDK
194     * {@code String.compareToIgnoreCase(String)} method.
195     * 
196     * @see HTMLNode#str
197     */
198    public static final Comparator<TextNodeIndex> comp3 =
199        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareToIgnoreCase(txni2.n.str);
200
201
202    // ********************************************************************************************
203    // ********************************************************************************************
204    // CharSequence Methods
205    // ********************************************************************************************
206    // ********************************************************************************************
207
208
209    /**
210     * Returns the char value at the specified index of the {@code public final String str} field
211     * of {@code 'this'} field {@code public final HTMLNode n}.
212     * An index ranges from zero to length() - 1. The first char value of the sequence is at index
213     * zero, the next at index one, and so on, as for array indexing.
214     * 
215     * <BR /><BR /><B>NOTE:</B> If the char value specified by the index is a surrogate, the
216     * surrogate value is returned.
217     * 
218     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
219     * cannot be modified by sub-classes.
220     * 
221     * @param index The index of the char value to be returned
222     * 
223     * @return The specified char value
224     */
225    public final char charAt(int index) { return n.str.charAt(index); }
226
227    /**
228     * Returns the length of the {@code public final String str} field of {@code 'this'} field
229     * {@code public final HTMLNode n}. The length is the number of 16-bit chars in the sequence.
230     * 
231     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
232     * cannot be modified by sub-classes.
233     * 
234     * @return the number of chars in {@code this.n.str}
235     */
236    public final int length() { return n.str.length(); }
237
238    /**
239     * Returns a CharSequence that is a subsequence of the {@code public final String str} field of
240     * {@code 'this'} field {@code public final HTMLNode n}.
241     * The subsequence starts with the char value at the specified index and ends with the char
242     * value at index end - 1. The length (in chars) of the returned sequence is end - start,  so
243     * if start == end then an empty sequence is returned.
244     * 
245     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
246     * cannot be modified by sub-classes.
247     * 
248     * @param start The start index, inclusive
249     * 
250     * @param end The end index, exclusive
251     * 
252     * @return The specified subsequence
253     */
254    public final CharSequence subSequence(int start, int end)
255    { return n.str.substring(start, end); }
256
257    /**
258     * Returns the {@code public final String str} field of {@code 'this'} field {@code public
259     * final HTMLNode n}.
260     * 
261     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
262     * cannot be modified by sub-classes.
263     * 
264     * @return A string consisting of exactly this sequence of characters.
265     * 
266     * @see HTMLNode#str
267     */
268    public final String toString()
269    { return n.str; }
270
271
272    // ********************************************************************************************
273    // ********************************************************************************************
274    // Replaceable Methods
275    // ********************************************************************************************
276    // ********************************************************************************************
277
278
279    public int originalSize() { return 1; }
280    public int currentSize() { return 1; };
281
282
283    public int originalLocationStart() { return index; }
284    public int originalLocationEnd() { return index + 1; }
285
286
287    public NODE firstCurrentNode() { return n; }
288    public NODE lastCurrentNode() { return n; }
289
290    private Vector<HTMLNode> CURRENT_NODES = null;
291
292    public Vector<HTMLNode> currentNodes()
293    {
294        if (CURRENT_NODES == null)  CURRENT_NODES = new Vector<>(1);
295        CURRENT_NODES.add(n);
296        return CURRENT_NODES;
297    }
298
299
300    public boolean addAllInto(Vector<HTMLNode> fileVec) { return fileVec.add(n); }
301
302    public boolean addAllInto(int index, Vector<HTMLNode> fileVec)
303    {
304        fileVec.insertElementAt(n, index);
305        return true;
306    }
307
308    public int update(Vector<HTMLNode> fileVec)
309    { fileVec.setElementAt(n, index);  return 0; }
310}