001package Torello.HTML;
002
003import Torello.Java.*;
004import java.util.*;
005
006/**
007 * <CODE>AUM (Attribute Update Mode) - Documentation.</CODE><BR /><BR />
008 * <EMBED CLASS='external-html' DATA-FILE-ID=AUM>
009 *
010 * @see Attributes#update(Vector, AUM, String, String, SD)
011 * @see Attributes#update(Vector, AUM, int, int, String, String, SD)
012 * @see Attributes#update(Vector, AUM, int[], String, String, SD)
013 */
014public enum AUM
015{
016    /**
017     * {@code Set}, when used as an Attribute Update Method, tells the HTML Element Attribute
018     * Update Logic to either <B>1)</B> replace the current
019     * attribute-<B STYLE="color: red;">value</B> with the new text-{@code String}, or <B>2)</B> If
020     * there is no attribute <B STYLE="color: red;">key-value</B> with the provided inner-tag
021     * <B STYLE="color: red;">name</B>, then to create a new attribute for the HTML Element for the
022     * provided attribute-<B STYLE="color: red;">key</B> and <B STYLE="color: red;">value</B> and
023     * insert this attribute <B STYLE="color: red;">key-value</B> pair into the element.
024     *
025     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
026     * 
027     * <DIV CLASS="SNIP">{@code
028     * // String cur = tn.AV(innerTag);   int i;
029     * case Set:  return tn.setAV(innerTag, innerTagValue, quote);
030     * }</DIV>
031     *
032     * <DIV CLASS="EXAMPLE-SCROLL">{@code
033     * // Example 1
034     * String   innerTag        = "target";
035     * String   innerTagValue   = "_BLANK";
036     * AUM      mode            = AUM.Set;
037     * TagNode  tn              = new TagNode("<A HREF='nextIndex.html'>");
038     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
039     * // newTN.str             ==> <A HREF='nextIndex.html' target='_BLANK'>
040     *                          // New 'target' attribute key-value pair inserted into HTML Element
041     *
042     * // Example 2
043     * String   innerTag        = "target";
044     * String   innerTagValue   = "_BLANK";
045     * AUM      mode            = AUM.Set;
046     * TagNode  tn              = new TagNode("<A HREF='nextIndex.html' TARGET='_Self'>");
047     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
048     * // newTN.str             ==> <A HREF='nextIndex.html' target='_BLANK'>
049     *                          // Old 'target' attribute key-value pair is replaced with new value
050     * }</DIV>
051     * 
052     * @see #update(TagNode, String, String, SD)
053     * @see HTMLNode#str
054     */
055    Set,
056
057    /**
058     * {@code Replace} when used as an Attribute Update Method, tells the HTML Element Attribute
059     * Update Logic to <I><B>replace</I></B> any attribute <B STYLE="color: red;">key-value</B>
060     * pair that the Element contains; <B><I>however</I></B> if there is no current 
061     * <B STYLE="color: red;">key-value</B> pair that has the provided attribute
062     * <B STYLE="color: red;">name</B>, then the HTML Element Node should be skipped, and left
063     * un-modified.
064     *
065     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
066     * 
067     * <DIV CLASS="SNIP">{@code
068     * // String cur = tn.AV(innerTag);   int i;
069     * case Replace:  if (cur != null) return tn.setAV(innerTag, innerTagValue, quote);
070     *                return null;
071     * }</DIV>
072     *
073     * <DIV CLASS="EXAMPLE-SCROLL">{@code
074     * // Example 1
075     * String   innerTag        = "style";
076     * String   innerTagValue   = "color: red;";
077     * AUM      mode            = AUM.Replace;
078     * TagNode  tn              = new TagNode("<A HREF='nextIndex.html' STYLE='font-weight: bold;'>");
079     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
080     * // newTN.str             ==> <A HREF='nextIndex.html' style='color: red;'>
081     *                          // Old 'style' attribute key-value pair is replaced with new value  
082     *
083     * // Example 2
084     * String   innerTag        = "style";
085     * String   innerTagValue   = "color: red;";
086     * AUM      mode            = AUM.Replace;
087     * TagNode  tn              = new TagNode("<A HREF='nextIndex.html'>");
088     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
089     * // newTN                 ==> null
090     *                          // NOTE: HTML Element left unchanged, because it did not actually
091     *                          //       have a 'style' attribute in the first place. 
092     *                          //       A return value of 'null' implies this AUM does not result
093     *                          //       in a replacement or update for the TagNode passed.
094     * }</DIV>
095     * 
096     * @see #update(TagNode, String, String, SD)
097     * @see HTMLNode#str
098     */ 
099    Replace,
100 
101    /**
102     * {@code RemoveSubString} when used as an Attribute Update Method, tells the HTML Element
103     * Attribute Update Logic to <I><B>remove</I></B> the first copy found of a provided sub-string
104     * from the attribute-<B STYLE="color: red;">value</B> whose attribute
105     * <B STYLE="color: red;">name</B> matches the provided inner-tag
106     * <B STYLE="color: red;">name</B>.
107     *
108     * <BR /><BR /><DIV CLASS="MISC_HILITE">
109     * <B>For Instance:</B> If AUM.RemoveSubString were used with an HTML Element
110     * that looked like: <SPAN STYLE="color: lightbrown; font-weight: bold;">
111     * <BR />{@code <DIV CLASS='MyClass MyPage Corporation123'>}</SPAN>
112     * 
113     * <BR /><BR />
114     * <B>Where:</B> {@code innerTag = "CLASS"} and {@code innerTagValue = "Corporation123"}
115     * 
116     * <BR /><BR /><B>Then:</B> The HTML Element would be updated to:
117     * <SPAN STYLE="color: blue; font-weight: bold;">
118     * <BR />{@code <DIV CLASS='MyClass MyPage '>}
119     * </SPAN>
120     * 
121     * <BR /><BR /><B>NOTE:</B> This uses Java's {@code String.indexOf(...)} method, and will only
122     * remove the first-instance of the substring.
123     * 
124     * <BR /><BR /><B>ALSO:</B> There is a remaining 'extra-space' that was not removed along with
125     * the {@code 'corporation123'} String.  Keep in mind white-space when using java to modify text.
126     * </DIV>
127     *
128     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
129     * 
130     * <DIV CLASS="SNIP">{@code
131     * // String cur = tn.AV(innerTag);   int i;
132     * case RemoveSubString:  if (cur != null) if ((i = cur.indexOf(innerTagValue)) != -1)
133     *                            return tn.setAV(innerTag, cur.replace(innerTagValue, ""), quote);
134     *                        return null;
135     * }</DIV>
136     * 
137     * @see #update(TagNode, String, String, SD)
138     * @see HTMLNode#str
139     */
140    RemoveSubString,
141
142    /**
143     * This performs the exact same routine as {@code AUM.RemoveSubstring}, however the
144     * text-{@code String} comparison ignores case for the alphabetic letters a..z.  This HTML
145     * Element Update Routine, just like the {@code AUM.RemoveSubstring}, also only removes the
146     * first instance found of the provided substring.
147     *
148     * <BR /><BR /><DIV CLASS="MISC_HILITE">
149     * <B>For Instance:</B> If AUM.RemoveSubString_CI were used with an HTML Element
150     * that looked like: <SPAN STYLE="color: lightbrown; font-weight: bold;">
151     * <BR />{@code <DIV CLASS='MyClass MyPage Corporation123' STYLE='FONT-WEIGHT: BOLD; COLOR:
152     * RED;'>}</SPAN>
153     * 
154     * <BR /><BR />
155     * <B>Where:</B> {@code innerTag = "STYLE"} and {@code innerTagValue = "color: red;"}
156     * 
157     * <BR /><BR /><B>Then:</B> The HTML Element would be updated to:
158     * <SPAN STYLE="color: blue; font-weight: bold;">
159     * <BR />{@code <DIV CLASS='MyClass MyPage Corporation123'STYLE='FONT-WEIGHT: BOLD; '>}</SPAN>
160     * 
161     * <BR /><BR /><B>NOTE:</B> This uses java's {@code StrCmpr.indexOfIgnoreCase(...)} method, and
162     * will only remove the first-instance of the substring (ignoring case).  In the original HTML
163     * Element, the words 'COLOR' and 'RED' were capitalized.  Using this 'Case-Insensitive'
164     * removal, the user can catch any version.  This, fortunately, is how CSS 'Style' Attributes
165     * work!
166     * 
167     * <BR /><BR /><B>ALSO:</B> There is a remaining 'extra-space' that was not removed along with
168     * the 'corporation123' string.  Keep in mind white-space when using java to modify text.
169     * </DIV>
170     *
171     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
172     * 
173     * <DIV CLASS="SNIP">{@code
174     * // String cur = tn.AV(innerTag);   int i;
175     * case RemoveSubString_CI:  if (cur != null) if ((i = StrCmpr.indexOfIgnoreCase(cur, innerTagValue)) != -1)
176     *                               return tn.setAV(innerTag, cur.substring(0, i) + cur.substring(i + innerTagValue.length()), quote);
177     *                           return null;
178     * }</DIV>
179     * 
180     * @see #update(TagNode, String, String, SD)
181     * @see HTMLNode#str
182     */
183    RemoveSubString_CI,
184
185    /**
186     * {@code ConcatToStart} when used as an Attribute Update Method, tells the HTML Element
187     * Attribute Update Logic to <I><B>concatenate</I></B> the provided
188     * attribute-<B STYLE="color: red;">value</B> to <I><B>an already in place</B></I>
189     * attribute-<B STYLE="color: red;">value</B> before the beginning of the current
190     * attribute-<B STYLE="color: red;">value</B> {@code String}. <B><I>However</I></B> if there is
191     * no current <B STYLE="color: red;">key-value</B> pair that has the provided attribute
192     * <B STYLE="color: red;">name</B>, then the HTML Element Node should be skipped, and left
193     * un-modified.
194     *
195     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
196     * 
197     * <DIV CLASS="SNIP">{@code
198     * // String cur = tn.AV(innerTag);   int i;
199     * case ConcatToStart:  if (cur != null) return tn.setAV(innerTag, innerTagValue + cur, quote);
200     *                      return null;
201     * }</DIV>
202     *
203     * <BR /><DIV CLASS="EXAMPLE-SCROLL">{@code
204     * // Example 1
205     * String   innerTag        = "id";
206     * String   innerTagValue   = "JAVA-AUM-";
207     * AUM      mode            = AUM.ConcatToStart;
208     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ID='MyPage'>");
209     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
210     * // newTN.str             ==> <IMG SRC='img-123.jpg' id='JAVA-AUM-MyPage'>
211     *
212     * // Example 2
213     * String   innerTag        = "id";
214     * String   innerTagValue   = "JAVA-AUM-";
215     * AUM      mode            = AUM.ConcatToStart;
216     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
217     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
218     * // newTN                 ==> null
219     *                          // NOTE: HTML Element left unchanged, because it did not actually
220     *                          //       have an 'id' attribute in the first place. 
221     *                          //       A return value of 'null' implies this AUM does not result
222     *                          //       in a replacement or update for the TagNode passed.
223     * }</DIV>
224     * 
225     * @see #update(TagNode, String, String, SD)
226     * @see HTMLNode#str
227     */
228    ConcatToStart,
229
230    /**
231     * {@code ConcatToStart} when used as an Attribute Update Method, tells the HTML Element
232     * Attribute Update Logic to <I><B>concatenate</I></B> the provided
233     * attribute-<B STYLE="color: red;">value</B> to <I><B>an already in place</B></I>
234     * attribute-<B STYLE="color: red;">value</B> before the beginning of the current
235     * attribute-<B STYLE="color: red;">value</B> {@code String}. If there is no current
236     * <B STYLE="color: red;">key-value</B> pair that has the provided attribute
237     * <B STYLE="color: red;">name</B>, a new Inner-Tag <B STYLE="color: red;">key-value</B> pair
238     * should be added to the HTML Element Node using the provided
239     * <B STYLE="color: red;">key</B>-{@code String} and
240     * <B STYLE="color: red;">value</B>-{@code String}.
241     *
242     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
243     * 
244     * <DIV CLASS="SNIP">{@code
245     * // String cur = tn.AV(innerTag);   int i;
246     * case ConcatToStartOrSet:  if (cur != null) return tn.setAV(innerTag, innerTagValue + cur, quote);
247     *                           return tn.setAV(innerTag, innerTagValue, quote);
248     * }</DIV>
249     *
250     * <DIV CLASS="EXAMPLE-SCROLL">{@code
251     * // Example 1
252     * String   innerTag        = "alt";
253     * String   innerTagValue   = "This is a personal photo.";
254     * AUM      mode            = AUM.ConcatToStartOrSet;
255     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
256     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
257     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a personal photo.'>  
258     *                          // The original TagNode did not have an 'alt' Inner-Tag, but
259     *                          // because this AUM has the "OrSet" requirement, when a TagNode
260     *                          // that's lacking the requested Inner-Tag, the AUM.update method
261     *                          // will not return null, but instead create a new attribute
262     *                          // key-value pair, and set the value to the requested parameter.
263     *
264     * // Example 2
265     * String   innerTag        = "alt";
266     * String   innerTagValue   = "This is a personal photo.";
267     * AUM      mode            = AUM.ConcatToStartOrSet;
268     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ALT='Bob Wilson'>");
269     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
270     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a personal photo.Bob Wilson'> 
271     *                          // NOTE: There is no space between the period, and the beginning of the
272     *                          //       next sentence in the ALT Inner-Tag above! 
273     * }</DIV>
274     * 
275     * @see #update(TagNode, String, String, SD)
276     * @see Torello.HTML.HTMLNode#str
277     */
278    ConcatToStartOrSet,
279
280    /**
281     * This {@code AUM} enumerated type is precisely identical to the one named
282     * {@code ConcatToStart} - <I><B>except</B></I> that in the case where the inner-tag
283     * <B STYLE="color: red;">value</B> is appended, a space is added immediately after the newly
284     * added {@code String}-<B STYLE="color: red;">value</B> token. 
285     * 
286     * <BR /><BR /><SPAN STYLE="color: red;"><B>NOTE:</B></SPAN> The primary reason for adding
287     * this surprisingly subtle and minor difference is to remind users that keeping up with spaces
288     * when tweaking HTML inner-tags can be a bug source.
289     *
290     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
291     * 
292     * <DIV CLASS="SNIP">{@code
293     * // String cur = tn.AV(innerTag);   int i;
294     * case ConcatToStartAddSpace:  if (cur != null) return tn.setAV(innerTag, innerTagValue + ' ' + cur, quote);
295     *                              return null;
296     * }</DIV>
297     *
298     * <DIV CLASS="EXAMPLE-SCROLL">{@code
299     * // Example 1
300     * String   innerTag        = "id";
301     * String   innerTagValue   = "JAVA-AUM";
302     * AUM      mode            = AUM.ConcatToStartAddSpace;
303     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ID='MyPage'>");
304     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
305     * // newTN.str             ==> <IMG SRC='img-123.jpg' id='JAVA-AUM MyPage'>
306     *
307     * // Example 2
308     * String   innerTag        = "id";
309     * String   innerTagValue   = "JAVA-AUM";
310     * AUM      mode            = AUM.ConcatToStartAddSpace;
311     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
312     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
313     * // newTN                 ==> null
314     *                          // NOTE: HTML Element left unchanged, because it did not actually
315     *                          //       have an 'id' attribute in the first place. 
316     *                          //       A return value of 'null' implies this AUM does not result
317     *                          //       in a replacement or update for the TagNode passed.
318     * }</DIV>
319     * 
320     * @see #update(TagNode, String, String, SD)
321     * @see Torello.HTML.HTMLNode#str
322     */
323    ConcatToStartAddSpace,
324
325    /**
326     * This {@code AUM} enumerated type is precisely identical to the one named
327     * {@code ConcatToStartOrSet} - <I><B>except</B></I> that in the case where the inner-tag
328     * <B STYLE="color: red;">value</B> is appended (concatenated), a space is added immediately
329     * after the newly added {@code String}-<B STYLE="color: red;">value</B> token.
330     *
331     * <BR /><BR /><B>NOTE:</B> If there were no inner-tag <B STYLE="color: red;">key-value</B>
332     * pair, and a new one was added - then an extra space would, hopefully this is obvious,
333     * <I>then an extra space would not be needed</I>, and therefore it is not added.
334     *
335     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
336     * 
337     * <DIV CLASS="SNIP">{@code
338     * // String cur = tn.AV(innerTag);   int i;
339     * case ConcatToStartOrSetAddSpace:  if (cur != null) return tn.setAV(innerTag, innerTagValue + ' ' + cur, quote);
340     *                                   return tn.setAV(innerTag, innerTagValue, quote);
341     * }</DIV>
342     *
343     * <DIV CLASS="EXAMPLE-SCROLL">{@code
344     * // Example 1
345     * String   innerTag        = "alt";
346     * String   innerTagValue   = "This is a personal photo.";
347     * AUM      mode            = AUM.ConcatToStartOrSetAddSpace;
348     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ALT='Company XYZ'>");
349     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
350     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a personal photo. Company XYZ'>  
351     *
352     * // Example 2
353     * String   innerTag        = "alt";
354     * String   innerTagValue   = "This is a personal photo.";
355     * AUM      mode            = AUM.ConcatToStartOrSetAddSpace;
356     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
357     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
358     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a personal photo.'>  
359     * }</DIV>
360     * 
361     * @see #update(TagNode, String, String, SD)
362     * @see Torello.HTML.HTMLNode#str
363     */
364    ConcatToStartOrSetAddSpace,
365
366    /**
367     * {@code ConcatToEnd} when used as an Attribute Update Method, tells the HTML Element
368     * Attribute Update Logic to <I><B>concatenate</I></B> the provided
369     * attribute-<B STYLE="color: red;">value</B> to <I><B>an already in place</B></I>
370     * attribute-<B STYLE="color: red;">value</B> at the end of the current
371     * attribute-<B STYLE="color: red;">value</B> {@code String}.  <B><I>However</I></B> if there
372     * is no current <B STYLE="color: red;">key-value</B> pair that has the provided attribute
373     * <B STYLE="color: red;">name</B>, then the HTML Element Node should be skipped, and left
374     * un-modified.
375     *
376     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
377     * 
378     * <DIV CLASS="SNIP">{@code
379     * // String cur = tn.AV(innerTag);   int i;
380     * case ConcatToEnd:  if (cur != null) return tn.setAV(innerTag, cur + innerTagValue, quote);
381     *                    return null;
382     * }</DIV>
383     *
384     * <DIV CLASS="EXAMPLE-SCROLL">{@code
385     * // Example 1
386     * String   innerTag        = "alt";
387     * String   innerTagValue   = "Photo of Friends";
388     * AUM      mode            = AUM.ConcatToEnd;
389     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ID='MyPage'>");
390     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
391     * // newTN                 ==> null
392     *                          // NOTE: HTML Element left unchanged, because it did not actually
393     *                          //       have an 'alt' attribute in the first place. 
394     *                          //       A return value of 'null' implies this AUM does not result
395     *                          //       in a replacement or update for the TagNode passed.
396     *
397     * // Example 2
398     * String   innerTag        = "alt";
399     * String   innerTagValue   = " - Photo of Friends";
400     * AUM      mode            = AUM.ConcatToEnd;
401     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ALT='Bob Wilson'>");
402     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
403     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='Bob Wilson - Photo of Friends'> 
404     * }</DIV>
405     * 
406     * @see #update(TagNode, String, String, SD)
407     * @see Torello.HTML.HTMLNode#str
408     */
409    ConcatToEnd,
410
411    /**
412     * {@code ConcatToEnd} when used as an Attribute Update Method, tells the HTML Element
413     * Attribute Update Logic to <I><B>concatenate</I></B> the provided
414     * attribute-<B STYLE="color: red;">value</B> to <I><B>an already in place</B></I>
415     * attribute-<B STYLE="color: red;">value</B> at the end of the current
416     * attribute-<B STYLE="color: red;">value</B> {@code String}.  If there is no current
417     * <B STYLE="color: red;">key-value</B> pair that has the provided attribute
418     * <B STYLE="color: red;">name</B>, a new Inner-Tag <B STYLE="color: red;">key-value</B> pair
419     * should be added to the HTML Element Node using the provided
420     * <B STYLE="color: red;">key</B>-{@code String} and
421     * <B STYLE="color: red;">value</B>-{@code String}.
422     *
423     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
424     * 
425     * <DIV CLASS="SNIP">{@code
426     * // String cur = tn.AV(innerTag);   int i;
427     * case ConcatToEndOrSet:  if (cur != null) return tn.setAV(innerTag, cur + innerTagValue, quote);
428     *                         return tn.setAV(innerTag, innerTagValue, quote);
429     * }</DIV>
430     *
431     * <DIV CLASS="EXAMPLE-SCROLL">{@code
432     * // Example 1
433     * String   innerTag        = "alt";
434     * String   innerTagValue   = " - This is a personal photo.";
435     * AUM      mode            = AUM.ConcatToEndOrSet;
436     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ALT='Larry'>");
437     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
438     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='Larry - This is a personal photo.'>
439     *                          // NOTE: There is no space between the period, and the beginning of
440     *                          //       the next sentence in the ALT Inner-Tag above!  
441     *
442     * // Example 2
443     * String   innerTag        = "alt";
444     * String   innerTagValue   = "This is a personal photo.";
445     * AUM      mode            = AUM.ConcatToEndOrSet;
446     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
447     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
448     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a personal photo.'>
449     *                          // The original TagNode did not have an 'alt' Inner-Tag, but
450     *                          // because this AUM has the "OrSet" requirement, when a TagNode
451     *                          // that's lacking the requested Inner-Tag, the AUM.update method
452     *                          // will not return null, but instead create a new attribute
453     *                          // key-value pair, and set the value to the requested parameter.
454     * }</DIV>
455     * 
456     * @see #update(TagNode, String, String, SD)
457     * @see Torello.HTML.HTMLNode#str
458     */
459    ConcatToEndOrSet,
460
461    /**
462     * This {@code AUM} enumerated type is precisely identical to the one named {@code ConcatToEnd}
463     * - <I><B>except</B></I> that in the case where the inner-tag <B STYLE="color: red;">value</B>
464     * is appended, a space is added immediately before the newly added
465     * {@code String}-<B STYLE="color: red;">value</B> token.
466     * 
467     * <BR /><BR /><SPAN STYLE="color: red;">NOTE:</SPAN> The primary reason for adding this
468     * surprisingly subtle and minor difference is to remind users that keeping up with spaces when
469     * tweaking HTML inner-tags can be a bug source.
470     *
471     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
472     * 
473     * <DIV CLASS="SNIP">{@code
474     * // String cur = tn.AV(innerTag);   int i;
475     * case ConcatToEndAddSpace:
476     *      if (cur != null) return tn.setAV(innerTag, cur + ' ' + innerTagValue, quote);
477     *      return null;
478     * }</DIV>
479     *
480     * <DIV CLASS="EXAMPLE-SCROLL">{@code
481     * // Example 1
482     * String   innerTag        = "id";
483     * String   innerTagValue   = "JAVA-AUM-EXAMPLE";
484     * AUM      mode            = AUM.ConcatToEndAddSpace;
485     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
486     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
487     * // newTN                 ==> null
488     *                          // NOTE: HTML Element left unchanged, because it did not actually
489     *                          //       have an 'id' attribute in the first place. 
490     *                          //       A return value of 'null' implies this AUM does not result
491     *                          //       in a replacement or update for the TagNode passed.
492     *
493     * // Example 2
494     * String   innerTag        = "id";
495     * String   innerTagValue   = "JAVA-AUM-EXAMPLE";
496     * AUM      mode            = AUM.ConcatToEndAddSpace;
497     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ID='MyClass'>");
498     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
499     * // newTN.str             ==> <IMG SRC='img-123.jpg' id='MyClass JAVA-AUM-EXAMPLE'>
500     * }</DIV>
501     * 
502     * @see #update(TagNode, String, String, SD)
503     * @see Torello.HTML.HTMLNode#str
504     */
505    ConcatToEndAddSpace,
506
507    /**
508     * This {@code AUM} enumerated type is precisely identical to the one named {@code ConcatToEnd}
509     * - <I><B>except</B></I> that in the case where the inner-tag <B STYLE="color: red;">value</B>
510     * is appended, a space is added immediately before the newly added
511     * {@code String}-<B STYLE="color: red;">value</B> token.
512     *
513     * <BR /><BR /><B>NOTE:</B> If there were no inner-tag <B STYLE="color: red;">key-value</B>
514     * pair, and a new one was added - then an extra space would, hopefully this is obvious,
515     * <I>then an extra space would not be needed</I>, and therefore it is not added.
516     *
517     * <BR /><BR />Here is how the HTML Element Attribute Update is Performed:
518     * 
519     * <DIV CLASS="SNIP">{@code
520     * // String cur = tn.AV(innerTag);   int i;
521     * case ConcatToEndOrSetAddSpace:
522     *      if (cur != null) return tn.setAV(innerTag, cur + ' ' + innerTagValue, quote);
523     *          return tn.setAV(innerTag, innerTagValue, quote);
524     * }</DIV>
525     *
526     * <DIV CLASS="EXAMPLE-SCROLL">{@code
527     * // Example 1
528     * String   innerTag        = "alt";
529     * String   innerTagValue   = "This is a corporate photo.";
530     * AUM      mode            = AUM.ConcatToEndOrSetAddSpace;
531     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg'>");
532     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
533     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='This is a corporate photo.'> 
534     *
535     * // Example 2
536     * String   innerTag        = "alt";
537     * String   innerTagValue   = "This is a corporate photo.";
538     * AUM      mode            = AUM.ConcatToEndOrSetAddSpace;
539     * TagNode  tn              = new TagNode("<IMG SRC='img-123.jpg' ALT='Bob'>");
540     * TagNode  newTN           = mode.update(tn, innerTag, innerTagValue, SD.SingleQuote);
541     * // newTN.str             ==> <IMG SRC='img-123.jpg' alt='Bob - This is a corporate photo.'
542     * }</DIV>
543     * 
544     * @see #update(TagNode, String, String, SD)
545     * @see Torello.HTML.HTMLNode#str
546     */
547    ConcatToEndOrSetAddSpace;
548
549    /**
550     * This performs the Update corresponding to the Attribute-Update-Mode for the particular
551     * AUM instance for {@code 'this'} enumerated-type object reference.
552     * 
553     * @param tn This HTML Element TagNode on which the update shall be performed.
554     * @param innerTag The Inner-Tag Key Name to look for inside the HTML Element. 
555     * @param innerTagValue The Inner-Tag Value to update, remove, concatenate, append or set.
556     * 
557     * @param quote This is a major issue in HTML / Java Programming.  The best thing to do is
558     * to not try to solve this problem at the lower-level, but rather propagate it up.
559     * 
560     * @return a newly updated or modified TagNode reference object.  If the update mode did not
561     * permit an attribute removal, update, or addition, then 'null' shall be returned.  Again,
562     * if 'null' is returned, it means the TagNode did not change - or, rather - <I>did not need
563     * to be changed as per the requirements of the chosen Attribute Update Method (AUM).</I>
564     */
565    public final TagNode update(TagNode tn, String innerTag, String innerTagValue, SD quote)
566    {
567        String cur = tn.AV(innerTag);
568        int i;
569
570        switch (this)
571        {
572            case Set:
573                return tn.setAV(innerTag, innerTagValue, quote);
574
575            case Replace:
576                if (cur != null) return tn.setAV(innerTag, innerTagValue, quote);
577                return null;
578
579            case RemoveSubString:
580
581                if ((cur != null) && ((i = cur.indexOf(innerTagValue)) != -1))
582                    return tn.setAV(innerTag, cur.replace(innerTagValue, ""), quote);
583
584                return null;
585
586            case RemoveSubString_CI:
587
588                if ((cur != null) && ((i = StrIndexOf.first_CI(cur, innerTagValue)) != -1))
589                    return tn.setAV(innerTag, cur.substring(0, i) +
590                        cur.substring(i + innerTagValue.length()), quote);
591
592                return null;
593
594            case ConcatToStart:
595                if (cur != null) return tn.setAV(innerTag, innerTagValue + cur, quote);
596                return null;
597
598            case ConcatToStartOrSet:
599                if (cur != null) return tn.setAV(innerTag, innerTagValue + cur, quote);
600                return tn.setAV(innerTag, innerTagValue, quote);
601
602            case ConcatToStartAddSpace:
603                if (cur != null) return tn.setAV(innerTag, innerTagValue + ' ' + cur, quote);
604                return null;
605
606            case ConcatToStartOrSetAddSpace:
607                if (cur != null) return tn.setAV(innerTag, innerTagValue + ' ' + cur, quote);
608                return tn.setAV(innerTag, innerTagValue, quote);
609
610            case ConcatToEnd:
611                if (cur != null) return tn.setAV(innerTag, cur + innerTagValue, quote);
612                return null;
613
614            case ConcatToEndOrSet:
615                if (cur != null) return tn.setAV(innerTag, cur + innerTagValue, quote);
616                return tn.setAV(innerTag, innerTagValue, quote);
617
618            case ConcatToEndAddSpace:
619                if (cur != null) return tn.setAV(innerTag, cur + ' ' + innerTagValue, quote);
620                return null;
621
622            case ConcatToEndOrSetAddSpace:
623                if (cur != null) return tn.setAV(innerTag, cur + ' ' + innerTagValue, quote);
624                return tn.setAV(innerTag, innerTagValue, quote);
625
626            default: throw new UnreachableError();
627        }
628    }
629}