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}