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    // ********************************************************************************************
123    // java.lang.Object Methods
124    // ********************************************************************************************
125    // ********************************************************************************************
126
127
128    /**
129     * Java's {@code public boolean equals(Object o)} requirements.
130     * 
131     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
132     * 
133     * <BR />This method is final, and cannot be modified by sub-classes.
134     * 
135     * @param o This may be any Java Object, but only ones of {@code 'this'} type whose
136     * internal-values are identical will bring this method to return true.
137     * 
138     * @return {@code TRUE} If {@code 'this'} equals another object {@code HTMLNode}.
139     */
140    public final boolean equals(Object o)
141    {
142        if (o == null) return false;
143        if (o == this) return true;
144
145        if (! this.getClass().equals(o.getClass())) return false;
146
147        NodeIndex<?> other = (NodeIndex) o;
148
149        return other.n.str.equals(this.n.str) && (other.index == this.index);
150    }
151
152    /**
153     * Java's hash-code requirement.
154     * 
155     * @return A hash-code that may be used when storing this node in a java hashed-collection.
156     * The {@link #index} of this {@code NodeIndex} ought to be be a unique hash.
157     */
158    public int hashCode() { return index; }
159
160    /**
161     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
162     * using the vector-index position.
163     * 
164     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
165     * cannot be modified by sub-classes.
166     * 
167     * @param ni Any other {@code NodeIndex} to be compared to {@code 'this' NodeIndex}
168     * 
169     * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean
170     * compareTo(T t)} method requirements.
171     * 
172     * @see #index
173     */
174    // @SuppressWarnings("rawtypes")
175    // public final int compareTo(NodeIndex ni)
176    // { return this.index - ni.index; }
177
178    /**
179     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
180     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
181     * JDK package {@code java.util.*;}
182     * 
183     * <BR /><BR /><B CLASS=JDDescLabel>Comparitor Heuristic:</B>
184     * 
185     * <BR />This version utilizes the standard JDK method {@code String.compareTo(String)}.
186     * 
187     * @see HTMLNode#str
188     */
189    public static final Comparator<TextNodeIndex> comp2 =
190        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareTo(txni2.n.str);
191    
192    /**
193     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
194     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
195     * JDK package {@code java.util.*;}
196     * 
197     * <BR /><BR /><B CLASS=JDDescLabel>Comparitor Heuristic:</B>
198     * 
199     * <BR />This version utilizes the standard JDK method
200     * {@code String.compareToIgnoreCase(String)}.
201     * 
202     * @see HTMLNode#str
203     */
204    public static final Comparator<TextNodeIndex> comp3 =
205        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareToIgnoreCase(txni2.n.str);
206
207
208    // ********************************************************************************************
209    // ********************************************************************************************
210    // CharSequence Methods
211    // ********************************************************************************************
212    // ********************************************************************************************
213
214
215    /**
216     * Returns the char value at the specified index of the {@code public final String str} field
217     * of {@code 'this'} field {@code public final HTMLNode n}.
218     * An index ranges from zero to length() - 1. The first char value of the sequence is at index
219     * zero, the next at index one, and so on, as for array indexing.
220     * 
221     * <BR /><BR />If the char value specified by the index is a surrogate, the surrogate value is
222     * returned.
223     * 
224     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
225     * 
226     * <BR />This method is final, and cannot be modified by sub-classes.
227     * 
228     * @param index The index of the char value to be returned
229     * 
230     * @return The specified char value
231     */
232    public final char charAt(int index) { return n.str.charAt(index); }
233
234    /**
235     * Returns the length of the {@code public final String str} field of {@code 'this'} field
236     * {@code public final HTMLNode n}. The length is the number of 16-bit chars in the sequence.
237     * 
238     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
239     * 
240     * <BR />This method is final, and cannot be modified by sub-classes.
241     * 
242     * @return the number of chars in {@code this.n.str}
243     */
244    public final int length() { return n.str.length(); }
245
246    /**
247     * Returns a CharSequence that is a subsequence of the {@code public final String str} field of
248     * {@code 'this'} field {@code public final HTMLNode n}.
249     * The subsequence starts with the char value at the specified index and ends with the char
250     * value at index end - 1. The length (in chars) of the returned sequence is end - start,  so
251     * if start == end then an empty sequence is returned.
252     * 
253     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
254     * 
255     * <BR />This method is final, and cannot be modified by sub-classes.
256     * 
257     * @param start The start index, inclusive
258     * 
259     * @param end The end index, exclusive
260     * 
261     * @return The specified subsequence
262     */
263    public final CharSequence subSequence(int start, int end)
264    { return n.str.substring(start, end); }
265
266    /**
267     * Returns the {@code public final String str} field of {@code 'this'} field {@code public
268     * final HTMLNode n}.
269     * 
270     * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B>
271     * 
272     * <BR />This method is final, and cannot be modified by sub-classes.
273     * 
274     * @return A string consisting of exactly this sequence of characters.
275     * 
276     * @see HTMLNode#str
277     */
278    public final String toString()
279    { return n.str; }
280
281
282    // ********************************************************************************************
283    // ********************************************************************************************
284    // Replaceable Methods
285    // ********************************************************************************************
286    // ********************************************************************************************
287
288
289    public int originalSize() { return 1; }
290    public int currentSize() { return 1; };
291
292
293    public int originalLocationStart() { return index; }
294    public int originalLocationEnd() { return index + 1; }
295
296
297    public NODE firstCurrentNode() { return n; }
298    public NODE lastCurrentNode() { return n; }
299
300    private Vector<HTMLNode> CURRENT_NODES = null;
301
302    public Vector<HTMLNode> currentNodes()
303    {
304        if (CURRENT_NODES == null)  CURRENT_NODES = new Vector<>(1);
305        CURRENT_NODES.add(n);
306        return CURRENT_NODES;
307    }
308
309
310    public boolean addAllInto(Vector<HTMLNode> fileVec) { return fileVec.add(n); }
311
312    public boolean addAllInto(int index, Vector<HTMLNode> fileVec)
313    {
314        fileVec.insertElementAt(n, index);
315        return true;
316    }
317
318    public int update(Vector<HTMLNode> fileVec)
319    { fileVec.setElementAt(n, index);  return 0; }
320}