001package Torello.HTML;
002
003import java.util.*;
004import java.util.function.BiConsumer;
005import java.util.concurrent.locks.*;
006
007import static Torello.Java.C.*;
008
009import Torello.Java.LV;
010
011import Torello.JavaDoc.StaticFunctional;
012import Torello.JavaDoc.Excuse;
013
014/**
015 * A fast way to print Web-Page {@code Vector's} to a {@code String}.
016 *
017 * <EMBED CLASS='external-html' DATA-FILE-ID=DEBUG>
018 */
019@StaticFunctional(Excused="lastWasNewLine", Excuses=Excuse.FLAG)
020public class Debug
021{
022    private Debug() { }
023
024    /**
025     * Convenience Method.
026     * <BR />Invokes: {@link #print(Vector, int, int, BiConsumer)}
027     * <BR />Requests: Print entire {@code 'page' (Vector)}
028     */
029    public static String print
030        (Vector<? extends HTMLNode> page, BiConsumer<HTMLNode, StringBuffer> printerVersion)
031    { return print(page, 0, -1, printerVersion); }
032
033    /**
034     * Convenience Method.
035     * <BR />Invokes: {@link #print(Vector, int, int, BiConsumer)}
036     * <BR />Requests: Print entire {@code SubSection}
037     */
038    public static String print(SubSection sec, BiConsumer<HTMLNode, StringBuffer> printerVersion)
039    { return print(sec.html, 0, -1, printerVersion); }
040
041    /**
042     * Convenience Method.
043     * <BR />Invokes: {@link #print(Vector, int, int, BiConsumer)}
044     * <BR />Requests: Print {@code 'page'} sub-range defined by parameter {@code 'dp'}
045     */
046    public static String print(
047            Vector<? extends HTMLNode> page, DotPair dp,
048            BiConsumer<HTMLNode, StringBuffer> printerVersion
049        )
050    { return print(page, dp.start, dp.end + 1, printerVersion); } 
051
052    /**
053     * Converts HTML to a {@code String} - adding readable notes &amp; messages.  This will print
054     * every node in the vectorized-html between starting-index {@code int sPos} (inclusively) and
055     * ending-index {@code int ePos}, exclusively.
056     * 
057     * @param page Any vectorized-html page or sub-page.
058     * 
059     * @param sPos The printing of nodes will begin at position {@code 'sPos'} - inclusively.
060     * 
061     * @param ePos The node at element-position will not be printed (exclusive), and the one
062     * previous shall print.
063     * 
064     * @param printerVersion The complicated-looking function-pointer comes from the package
065     * {@code 'java.util.function.'} The literal code to pass to this parameter would be:
066     * <SPAN STYLE="color: blue; font-weight: bold;">Debug::A, Debug::B ... Debug::K</SPAN>.  The
067     * programmer may also create a print-function if so desired, and pass that using a
068     * function-pointer or a {@code lambda-expression}
069     * 
070     * @return a pretty printed {@code String} of the nodes in this {@code Vector}.
071     * 
072     * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=VIOOBEX>
073     * 
074     * @see LV
075     */
076    public static String print(
077        Vector<? extends HTMLNode> page, int sPos, int ePos,
078        BiConsumer<HTMLNode, StringBuffer> printerVersion
079    )
080    {
081        LV              l   = new LV(page, sPos, ePos);
082        StringBuffer    sb  = new StringBuffer();
083
084        for (int i=l.start; i < l.end; i++)
085            printerVersion.accept(page.elementAt(i), sb);
086
087        return sb.toString();
088    }
089
090    /**
091     * Converts HTML to a {@code String} - adding readable notes &amp; messages.  This version
092     * shall only print nodes whose index "is pointed to" by the elements of the position-index
093     * array parameter {@code int[] posArr}.
094     * 
095     * @param page Any vectorized-html page or sub-page.
096     * 
097     * @param posArr This is an array of index-pointers into the vectorized-html webpage
098     * parameter 'page.'  These arrays are usually created by calls to the {@code package
099     * NodeSearch} using classes with the <B>{@code 'Find'} Key-Word</B>.  Such classes return
100     * integer-arrays of pointers to nodes that matched a specific search criteria.
101     * 
102     * @param printerVersion The complicated-looking function-pointer comes from the package
103     * 'java.util.function.' The literal code to pass to this parameter would be:
104     * <SPAN STYLE="color: blue; font-weight: bold;">Debug::A, Debug::B ... Debug::K</SPAN>.  The
105     * programmer may also create a print-function if so desired, and pass that using a
106     * function-pointer or a {@code lambda-expression}.
107     * 
108     * @return a pretty printed {@code String} of the nodes in this {@code Vector} pointed-to by
109     * the elements of {@code 'posArr'}
110     * 
111     * @throws ArrayIndexOutOfBoundsException If any of the elements in {@code 'posArr'} contain
112     * index-pointers that are out of range of {@code Vector} parameter {@code 'page'}, then java
113     * will, naturally, throw this exception.
114     */
115    public static String print(
116        Vector<? extends HTMLNode> page, int[] posArr,
117        BiConsumer<HTMLNode, StringBuffer> printerVersion
118    )
119    {
120        StringBuffer sb  = new StringBuffer();
121        for (int i : posArr) printerVersion.accept(page.elementAt(i), sb);
122        return sb.toString();
123    }
124
125    /**
126     * Converts HTML to a {@code String} - adding readable notes &amp; messages.  This version
127     * shall only print nodes whose index "is pointed to" by the elements of the position-index
128     * array parameter {@code int[] posArr}.
129     * 
130     * <BR /><BR /><B CLASS=JDDescLabel>Note about Usability:</B>
131     * 
132     * <BR />This version of print can be invaluable during debugging when trolling through pages
133     * of HTML is reduced to only the indexes that are indicated by an index-pointer array.  The
134     * addition of a "radix" means that some nodes before and after the identified node can be
135     * looked at too.
136     * 
137     * @param page Any vectorized-html page or sub-page.
138     * 
139     * @param posArr This is an array of index-pointers into the vectorized-html webpage
140     * parameter {@code 'page'}.  These arrays are usually created by calls to the {@code package
141     * NodeSearch} using classes with the <B>{@code 'Find'} Key-Word</B>.  Such classes return
142     * integer-arrays of pointers to nodes that matched a specific search criteria.
143     * 
144     * @param radix The number of nodes, in both the forward and reverse directions, to include
145     * in the output for a match.
146     * 
147     * @param nodesHaveBeenSkippedString This will be printed whenever the print-logic has skipped
148     * nodes in the list during printing.  An example of a good {@code String} to use would just be
149     * {@code Sting s = "***** Nodes Skipped *****\n";}, but any choice will do - so long as it
150     * gives the appearance the during printing there are "blank spots" that skipped some of the
151     * content of the html.
152     * 
153     * @param addColorCurlyBracesToRequestedNodes If this is {@code TRUE}, and the
154     * {@code class Shell.C} has its color {@code String} evaluated, because the program is running
155     * on some acceptable version of UNIX, then a bright-green colored curly-brace set will
156     * surround each node that is explicitly a member of the index-pointer-array, parameter
157     * {@code 'posArr'}
158     * 
159     * <BR /><BR /><B>NOTE:</B> If this is unclear, this method prints every node that is
160     * pointed-to by the {@code 'posArr'} parameter. In addition to these nodes, it will print
161     * {@code 'radix'} nodes before and {@code 'radix'} nodes after each of the elements pointed to
162     * by the {@code 'posArr'} parameter.  When viewing the output, if it is important to know
163     * which nodes are explicitly in the 'request-list' then adding bright-green curly braces to
164     * those output nodes will differentiate them from other nodes that are being printed because
165     * of the {@code radix} parameter.
166     * 
167     * @param printerVersion The complicated-looking function-pointer comes from the package
168     * {@code 'java.util.function.'} The literal code to pass to this parameter would be:
169     * <SPAN STYLE="color: blue; font-weight: bold;">Debug::A, Debug::B ... Debug::K</SPAN>.  The
170     * programmer may also create a print-function if so desired, and pass that using a
171     * function-pointer or a {@code lambda-expression}
172     * 
173     * @return a pretty printed {@code String} of the nodes in this {@code Vector} pointed-to by
174     * the elements of {@code 'posArr'}, surrounded by {@code 'radix'} number of nodes in either
175     * direction.
176     * 
177     * @throws ArrayIndexOutOfBoundsException If any of the elements in {@code posArr} contain
178     * index-pointers that are out of range of {@code Vector}-parameter {@code 'page'}, then java
179     * will, naturally, throw this exception
180     * 
181     * @see Torello.Java.C
182     */
183    public static String print(
184        Vector<? extends HTMLNode> page, int[] posArr, int radix,
185        String nodesHaveBeenSkippedString,
186        boolean addColorCurlyBracesToRequestedNodes,
187        BiConsumer<HTMLNode, StringBuffer> printerVersion
188    )
189    {
190        StringBuffer sb = new StringBuffer();
191
192        // Used internally to print-curly braces
193        TreeSet<Integer> ts = null;
194
195        // Initialize it if the curly-braces are requested
196        if (addColorCurlyBracesToRequestedNodes)
197        {
198            ts = new TreeSet<>();
199            for (int pos : posArr) ts.add(Integer.valueOf(pos));
200        }
201
202        int start   = 0;
203        int end     = 0;
204
205        for (int i : posArr)
206        {
207            // Start at precisely the current index-pointer MINUS the radix.
208            // OR ... If the loop is about to "reprint" a node because the radix is larger than the
209            //        space between two consecutive nodes - then start at the node just after the
210            //        last node that was printed.
211
212            start = Math.max(i - radix, end + 1);
213    
214            // A large radix might get the loop past the end of the vector, AVOID THAT.
215            if (start > (page.size() - 1)) break;
216
217            // If the next node to be printed is immediately after the previous node that was
218            // printed IN THE UNDERLYING HTML, then no nodes have been skipped, so don't print the
219            // "nodesHaveBeenSkippedString" ... otherwise print it!
220
221            if (start > (end + 1)) sb.append(nodesHaveBeenSkippedString);
222
223            // Make sure not to go past the last node in the string, or exception will throw.
224            end = Math.min(i + radix, (page.size() - 1));
225
226            // It is possible that 'start' is greater than 'end' (too much overlap), in which case
227            // the outer loop will continue on to the next index-pointer.
228            // NOTE: uses 'j <= end' NOT 'j < end' !!! (TRICKY)
229
230            if (addColorCurlyBracesToRequestedNodes)
231
232                for (int j=start; j <= end; j++)
233                {
234                    boolean addColorBrackets = ts.contains(Integer.valueOf(j));
235
236                    if (addColorBrackets)
237                        sb.append(BGREEN + "{" + RESET);
238
239                    printerVersion.accept(page.elementAt(j), sb);
240
241                    if (addColorBrackets)
242                        sb.append(BGREEN + "}" + RESET);
243                }
244
245            else
246                for (int j=start; j <= end; j++)
247                    printerVersion.accept(page.elementAt(j), sb);
248        }
249
250        return sb.toString();
251    }
252
253
254    // ********************************************************************************************
255    // ********************************************************************************************
256    // Protected, Internal Print Methods
257    // ********************************************************************************************
258    // ********************************************************************************************
259
260
261    /**
262     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
263     * <CODE><B>Print Style 'A'</B></CODE> 
264     * 
265     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
266     * 
267     * @param sb the {@code StringBuffer} that is receiving the print command.
268     * 
269     * @see TagNode#str
270     */
271    public static void A(HTMLNode n, StringBuffer sb)
272    {
273        String name = n.getClass().getSimpleName();
274
275        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
276        // exception.
277
278        if (name.equals("")) name = "Anonymous Class";
279
280        sb.append("[" + name + ":" + n.str + "]");
281    }
282
283    /**
284     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
285     * <CODE><B>Print Style 'B'</B></CODE> 
286     * 
287     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
288     * 
289     * @param sb the {@code StringBuffer} that is receiving the print command.
290     * 
291     * @see TagNode#str
292     */
293    public static void B(HTMLNode n, StringBuffer sb)
294    {
295        String name = n.getClass().getSimpleName();
296
297        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
298        // exception.
299
300        if (name.equals("")) name = "Anonymous Class";
301
302        sb.append("[" + name + ", StrLen=" + n.str.length() + ": " + n.str + "]");
303    }
304
305    /**
306     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
307     * <CODE><B>Print Style 'C'</B></CODE> 
308     * 
309     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
310     * 
311     * @param sb the {@code StringBuffer} that is receiving the print command.
312     * 
313     * @see TagNode#str
314     * @see TagNode#tok
315     * @see TagNode#isClosing
316     */
317    public static void C(HTMLNode n, StringBuffer sb)
318    {
319        String name = n.getClass().getSimpleName();
320
321        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
322        // exception.
323
324        if  (name.equals("")) name = "Anonymous Class";
325
326        if (n.isTagNode())
327
328            sb.append(
329                "[" + name + ", n.tok=" + ((TagNode) n).tok + ", " +
330                "n.isClosing=" + ((TagNode) n).isClosing + ": " + n.str + "]"
331            );
332
333        else
334            sb.append("[" + name + ": " + n.str + "]");
335    }
336
337    /**
338     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
339     * <CODE><B>Print Style 'D'</B></CODE> 
340     * 
341     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
342     * @param sb the {@code StringBuffer} that is receiving the print command.
343     * 
344     * @see TagNode#str
345     * @see TagNode#tok
346     * @see TagNode#isClosing
347     */
348    public static void D(HTMLNode n, StringBuffer sb)
349    {
350        String name = n.getClass().getSimpleName();
351
352        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
353        // exception.
354
355        if  (name.equals("")) name = "Anonymous Class";
356
357        if (n.isTagNode())
358
359            sb.append(
360                "[" + name + ", StrLen=" + n.str.length() + ", n.tok=" + ((TagNode) n).tok + ", " +
361                "n.isClosing=" + ((TagNode) n).isClosing + ": " + n.str + "]"
362            );
363
364        else
365            sb.append("[" + name + ", StrLen=" + n.str.length() + ": " + n.str + "]");
366    }
367
368    /**
369     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
370     * <CODE><B>Print Style 'E'</B></CODE> 
371     * 
372     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
373     * @param sb the {@code StringBuffer} that is receiving the print command.
374     * 
375     * @see TagNode#str
376     * @see TagNode#tok
377     * @see TagNode#isClosing
378     */
379    public static void E(HTMLNode n, StringBuffer sb)
380    {
381        String name = n.getClass().getSimpleName();
382
383        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
384        // exception.
385
386        if  (name.equals("")) name = "Anonymous Class";
387
388        if (n.isTagNode())
389
390            sb.append(
391                "[" + name + ", StrLen=" + n.str.length() + ", n.tok=" + ((TagNode) n).tok + ", " +
392                "n.isClosing=" + ((TagNode) n).isClosing + "]\n[" + n.str + "]\n"
393            );
394
395        else
396            sb.append("[" + name + ", StrLen=" + n.str.length() + "]\n[" + n.str + "]\n");
397    }
398
399    /**
400     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
401     * <CODE><B>Print Style 'F'</B></CODE> 
402     * 
403     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
404     * @param sb the {@code StringBuffer} that is receiving the print command.
405     * 
406     * @see TagNode#str
407     * @see TagNode#isClosing
408     * @see TagNode#toStringAV()
409     */
410    public static void F(HTMLNode n, StringBuffer sb)
411    {
412        String name = n.getClass().getSimpleName();
413
414        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
415        // exception.
416
417        if (name.equals("")) name = "Anonymous Class";
418
419        if (n.isTagNode() && (! ((TagNode) n).isClosing))
420            sb.append(((TagNode) n).toStringAV());
421
422        else
423            sb.append("[" + name + ", StrLen=" + n.str.length() + "]\n[" + n.str + "]\n");
424    }
425
426    /** Method 'G' is a hack - uses a global variable - THIS IS A HACK.  DO NOT WORRY ABOUT IT. */
427    private static boolean lastWasNewLine = false;
428
429    /**
430     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
431     * <CODE><B>Print Style 'G'</B></CODE>
432     * 
433     * <BR /><BR /><B CLASS=JDDescLabel>Thread Safety Point:</B>
434     * 
435     * <BR />Print Style G <I>is not {@code Thread} safe!</I>.
436     * 
437     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
438     * @param sb the {@code StringBuffer} that is receiving the print command.
439     * 
440     * @see TagNode#str
441     * @see TagNode#tok
442     * @see TagNode#isClosing
443     * @see TagNode#toStringAV()
444     */
445    public static void G(HTMLNode n, StringBuffer sb)
446    {
447        String name = n.getClass().getSimpleName();
448
449        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
450        // exception.
451
452        if (name.equals("")) name = "Anonymous Class";
453
454        TagNode tn = null;
455
456        if (    n.isTagNode()
457            &&  (! (tn = (TagNode) n).isClosing)
458            &&  (tn.str.length() > (tn.tok.length() + 4))
459        )
460        {
461            sb.append((lastWasNewLine ? "" : "\n") + ((TagNode) n).toStringAV());
462            lastWasNewLine = true;
463        }
464
465        else
466        {
467            sb.append("[" + name + ", StrLen=" + n.str.length() + ": " + n.str + "]");
468            lastWasNewLine = false;
469        };
470    }
471
472    /**
473     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
474     * <CODE><B>Print Style 'H'</B></CODE> 
475     * 
476     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
477     * @param sb the {@code StringBuffer} that is receiving the print command.
478     * 
479     * @see C
480     * @see C#RESET
481     * @see C#BRED
482     * @see C#BCYAN
483     * @see TagNode#str
484     * @see TagNode#tok
485     * @see TagNode#isClosing
486     */
487    public static void H(HTMLNode n, StringBuffer sb)
488    {
489        String name = n.getClass().getSimpleName();
490
491        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
492        // exception.
493
494        if (name.equals("")) name = "Anonymous Class";
495
496        if (n.isTagNode())
497
498            sb.append(
499                "[" + name + ", StrLen=" + BCYAN + n.str.length() + RESET + ", " +
500                "n.tok=" + BCYAN + ((TagNode) n).tok + RESET +", " +
501                "n.isClosing=" + BCYAN + ((TagNode) n).isClosing + RESET + "]" +
502                "[" + BRED + n.str + RESET + "]"
503            );
504
505        else
506
507            sb.append(
508                "[" + name + ", StrLen=" + BCYAN + n.str.length() + RESET + ": " +
509                BRED + n.str + RESET + "]"
510            );
511    }
512
513    /**
514     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
515     * <CODE><B>Print Style 'I'</B></CODE> 
516     * 
517     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
518     * @param sb the {@code StringBuffer} that is receiving the print command.
519     * 
520     * @see C
521     * @see C#RESET
522     * @see C#BRED
523     * @see C#BCYAN
524     * @see TagNode#str
525     * @see TagNode#tok
526     */
527    public static void I(HTMLNode n, StringBuffer sb)
528    {
529        String name = n.getClass().getSimpleName();
530
531        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
532        // exception.
533        if (name.equals("")) name = "Anonymous Class";
534
535        if (n.isTagNode())
536
537            sb.append(
538                "[" + name + ", StrLen=" + BCYAN + n.str.length() + RESET + ", " +
539                "n.tok=" + BCYAN + ((TagNode) n).tok + RESET + ", " +
540                "n.isClosing=" + BCYAN + ((TagNode) n).isClosing + RESET + "]\n" +
541                "[" + BRED + n.str + RESET + "]\n"
542            );
543
544        else
545
546            sb.append(
547                "[" + name + ", StrLen=" + BCYAN + n.str.length() + RESET + "]\n" +
548                "[" + BRED + n.str + RESET + "]\n"
549            );
550    }
551
552    /**
553     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
554     * <CODE><B>Print Style 'J'</B></CODE> 
555     * 
556     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
557     * @param sb the {@code StringBuffer} that is receiving the print command.
558     * 
559     * @see C
560     * @see C#RESET
561     * @see C#BRED
562     * @see C#BYELLOW
563     * @see TagNode#str
564     */
565    public static void J(HTMLNode n, StringBuffer sb)
566    {
567        String name = n.getClass().getSimpleName();
568
569        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent
570        // exception.
571
572        if (name.equals("")) name = "Anonymous Class";
573
574        if (n.isTagNode())
575            sb.append("[" + BRED + n.str + RESET + "]");
576
577        else if (n.isCommentNode())
578            sb.append("[" + BYELLOW + n.str + RESET + "]");
579
580        else
581            sb.append("[" + n.str + "]");
582    }
583
584    /**
585     * Prints an HTML Element ({@code TagNode, TextNode} or {@code CommentNode}) using
586     * <CODE><B>Print Style 'K'</B></CODE> 
587     * 
588     * @param n An {@code HTMLNode} that will print to the {@code StringBuffer}
589     * @param sb the {@code StringBuffer} that is receiving the print command.
590     * 
591     * @see C
592     * @see C#RESET
593     * @see C#BRED
594     * @see C#BYELLOW
595     * @see TagNode#str
596     */
597    public static void K(HTMLNode n, StringBuffer sb)
598    {
599        String name = n.getClass().getSimpleName();
600
601        // Extremely Unlikely Programmer has extended HTMLNode, but just in case, to prevent exception.
602        if  (name.equals("")) name = "Anonymous Class";
603
604        if (n.isTagNode())
605            sb.append("[" + BRED + n.str + RESET + "]\n");
606
607        else if (n.isCommentNode())
608            sb.append("[" + BYELLOW + n.str + RESET + "]\n");
609
610        else
611            sb.append("[" + n.str + "]\n");
612    }
613}