1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package Torello.HTML;

import java.util.Vector;
import java.io.Serializable;
import java.util.Comparator;

/**
 * The abstract parent class of all three {@code NodeIndex} classes, {@link TagNodeIndex},
 * {@link TextNodeIndex} and {@link CommentNodeIndex}.
 * 
 * <BR /><BR /><EMBED CLASS="external-html" DATA-FILE-ID=NODE_INDEX>
 * 
 * @param <NODE> The class of {@code HTMLNode} represented by this {@code NodeIndex} instance.
 * @see HTMLNode
 * @see CommentNodeIndex
 * @see TagNodeIndex
 * @see TextNodeIndex
 */
@SuppressWarnings("rawtypes")
public abstract class NodeIndex<NODE extends HTMLNode>
    implements CharSequence, Serializable, Cloneable, Replaceable
{
    // ********************************************************************************************
    // ********************************************************************************************
    // Fields
    // ********************************************************************************************
    // ********************************************************************************************


    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUID"> */
    public static final long serialVersionUID = 1;

    /**
     * An index to a node from a web-page.   This index must point to a the exact same node inside
     * of a vectorized-html page as the node stored in member-field {@code HTMLNode 'n'}.  
     */
    public final int index;

    /**
     * A {@code HTMLNode} from a web-page.  This node is supposed to be the same node stored at the
     * index specified by member-field {@code int 'index'} of some vectorized-html web-page in
     * memory or on disk.
     */
    public NODE n;


    // ********************************************************************************************
    // ********************************************************************************************
    // Constructor
    // ********************************************************************************************
    // ********************************************************************************************


    /** 
     * a default constructor.  This assigns a value to the index field.
     * 
     * @param index This is the vector-index location of HTMLNode 'n' inside of a vectorized-HTML
     * web-page.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">STALE DATA NOTE:</B></SPAN> This class is a
     * minor-use class, not one of the primary data classes.  This instance shall become 'useless'
     * the moment the vector that was used to instantiate this class is modified, and the node 'n'
     * is no longer at vector-index 'index.'  These "NodeIndex" classes are retained, not
     * deprecated due to the fundamental nature of using the classes of the NodeSearch Package.
     * Data is easily made stale.  Generally, when modifying HTML Vectors, the easiest thing to do
     * is <I><B>to remember to modify a vector at specific locations by iterating from the end of
     * the vector, back to the beginning.</I></B>  This will generally prevent "state-data
     * vector-indexes" from rearing their ugly head.
     * 
     * @param n An HTMLNode that needs to be the node found in the underlying vector at
     * vector-index 'index.'
     *
     * @throws IndexOutOfBoundsException if {@code index} is negative, this exception is thrown.
     * @throws NullPointerException if {@code n} is null.
     */
    protected NodeIndex(int index, NODE n)
    {
        this.index = index;
        this.n = n;

        if (n == null)  throw new NullPointerException(
            "HTMLNode parameter 'n' to this constructor was passed a null value, but this " +
            "is not allowed here."
        );

        if (index < 0)  throw new IndexOutOfBoundsException(
            "Integer parameter 'index' to this constructor was passed a negative value: " +
            index
        );
    }

    /**
     * Simple dispatch method helper that switches on the class of input parameter {@code 'n'}.
     * 
     * @param n Any of the three Java HTML defined {@code HTMLNode} subclasses - {@link TagNode},
     * {@link TextNode} or {@code CommentNode}
     * 
     * @return A {@code NodeIndex} inheriting class that is appropriate to {@code 'n'}.
     * 
     * @throws IllegalArgumentException If the user has extended class {@code HTMLNode}, and passed
     * this unrecognized {@code HTMLNode} Type.
     */
    public static final NodeIndex<?> newNodeIndex(int index, HTMLNode n)
    {
        Class<?> newNodeClass = n.getClass();

        if (TagNode.class.isAssignableFrom(newNodeClass))
            return new TagNodeIndex(index, (TagNode) n);

        if (TextNode.class.isAssignableFrom(newNodeClass))
            return new TextNodeIndex(index, (TextNode) n);

        if (CommentNode.class.isAssignableFrom(newNodeClass))
            return new CommentNodeIndex(index, (CommentNode) n);

        throw new IllegalArgumentException
            ("Parameter 'n' has a Type that is an Unrecognized HTMLNode-SubClass Type");
    }

    // ********************************************************************************************
    // ********************************************************************************************
    // java.lang.Object Methods
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Java's {@code public boolean equals(Object o)} requirements.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @param o This may be any Java Object, but only ones of {@code 'this'} type whose
     * internal-values are identical will bring this method to return true.
     * 
     * @return <B>TRUE</B> If {@code 'this'} equals another object {@code HTMLNode.}
     */
    public final boolean equals(Object o)
    {
        NodeIndex<?> other;

        return (    this == o)
                || (    (o != null)
                    &&  (this.getClass().equals(o.getClass()))
                    &&  ((other = (NodeIndex) o).n.str.equals(this.n.str))
                    &&  (other.index == this.index));
    }

    /**
     * Java's hash-code requirement.
     * 
     * @return A hash-code that may be used when storing this node in a java hashed-collection.
     * The {@link #index} of this {@code NodeIndex} ought to be be a unique hash.
     */
    public int hashCode() { return index; }

    /**
     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
     * using the vector-index position.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @param ni Any other {@code NodeIndex} to be compared to {@code 'this' NodeIndex}
     * 
     * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean
     * compareTo(T t)} method requirements.
     * 
     * @see #index
     */
    // @SuppressWarnings("rawtypes")
    // public final int compareTo(NodeIndex ni)
    // { return this.index - ni.index; }

    /**
     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
     * JDK package {@code java.util.*;}
     * 
     * <BR /><BR /><B>NOTE:</B> This version utilizes the standard JDK
     * {@code String.compareTo(String)} method.
     * 
     * @see HTMLNode#str
     */
    public static final Comparator<TextNodeIndex> comp2 =
        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareTo(txni2.n.str);
    
    /**
     * This is an "alternative Comparitor" that can be used for sorting instances of this class.
     * It should work with the {@code Collections.sort(List, Comparator)} method in the standard
     * JDK package {@code java.util.*;}
     * 
     * <BR /><BR /><B>NOTE:</B> This version utilizes the standard JDK
     * {@code String.compareToIgnoreCase(String)} method.
     * 
     * @see HTMLNode#str
     */
    public static final Comparator<TextNodeIndex> comp3 =
        (TextNodeIndex txni1, TextNodeIndex txni2) -> txni1.n.str.compareToIgnoreCase(txni2.n.str);


    // ********************************************************************************************
    // ********************************************************************************************
    // CharSequence Methods
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Returns the char value at the specified index of the {@code public final String str} field
     * of {@code 'this'} field {@code public final HTMLNode n}.
     * An index ranges from zero to length() - 1. The first char value of the sequence is at index
     * zero, the next at index one, and so on, as for array indexing.
     * 
     * <BR /><BR /><B>NOTE:</B> If the char value specified by the index is a surrogate, the
     * surrogate value is returned.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @param index The index of the char value to be returned
     * 
     * @return The specified char value
     */
    public final char charAt(int index) { return n.str.charAt(index); }

    /**
     * Returns the length of the {@code public final String str} field of {@code 'this'} field
     * {@code public final HTMLNode n}. The length is the number of 16-bit chars in the sequence.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @return the number of chars in {@code this.n.str}
     */
    public final int length() { return n.str.length(); }

    /**
     * Returns a CharSequence that is a subsequence of the {@code public final String str} field of
     * {@code 'this'} field {@code public final HTMLNode n}.
     * The subsequence starts with the char value at the specified index and ends with the char
     * value at index end - 1. The length (in chars) of the returned sequence is end - start,  so
     * if start == end then an empty sequence is returned.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @param start The start index, inclusive
     * 
     * @param end The end index, exclusive
     * 
     * @return The specified subsequence
     */
    public final CharSequence subSequence(int start, int end)
    { return n.str.substring(start, end); }

    /**
     * Returns the {@code public final String str} field of {@code 'this'} field {@code public
     * final HTMLNode n}.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">FINAL METHOD:</B></SPAN> This method is final, and
     * cannot be modified by sub-classes.
     * 
     * @return A string consisting of exactly this sequence of characters.
     * 
     * @see HTMLNode#str
     */
    public final String toString()
    { return n.str; }


    // ********************************************************************************************
    // ********************************************************************************************
    // Replaceable Methods
    // ********************************************************************************************
    // ********************************************************************************************


    public int originalSize() { return 1; }
    public int currentSize() { return 1; };


    public int originalLocationStart() { return index; }
    public int originalLocationEnd() { return index + 1; }


    public NODE firstCurrentNode() { return n; }
    public NODE lastCurrentNode() { return n; }

    private Vector<HTMLNode> CURRENT_NODES = null;

    public Vector<HTMLNode> currentNodes()
    {
        if (CURRENT_NODES == null)  CURRENT_NODES = new Vector<>(1);
        CURRENT_NODES.add(n);
        return CURRENT_NODES;
    }


    public boolean addAllInto(Vector<HTMLNode> fileVec) { return fileVec.add(n); }

    public boolean addAllInto(int index, Vector<HTMLNode> fileVec)
    {
        fileVec.insertElementAt(n, index);
        return true;
    }

    public int update(Vector<HTMLNode> fileVec)
    { fileVec.setElementAt(n, index);  return 0; }
}