001package Torello.HTML.Tools.JavaDoc;
002
003import Torello.HTML.Tools.JavaDoc.JavaDocError;
004import Torello.Java.EXCC;
005import Torello.Java.StorageWriter;
006import Torello.Java.StrIndent;
007import Torello.Java.UnreachableError;
008import Torello.Java.Shell.C;
009
010import java.util.Vector;
011
012/**
013 * A replacement for <CODE>System&#46;out, System&#46;err</CODE> and even the {@link StorageWriter}
014 * class used to send error messages to the terminal about upgrade progress.  
015 * 
016 * <BR /><BR /><EMBED CLASS="external-html" DATA-FILE-ID="JDMESSAGER">
017 */
018public class Messager
019{
020    private Messager() { }
021
022    // ********************************************************************************************
023    // ********************************************************************************************
024    // Main Fields
025    // ********************************************************************************************
026    // ********************************************************************************************
027
028    // Error Message for {@code TypeNotPresentException}
029    static final String TNPE = 
030        "TypeNotPresentException thrown attempting to load Configuration Class.\n" +
031        "Class requires correct Package-Name, options are:\n" +
032        "    1) No Package-Name  2) Same Package-Name as the Package it's configuring";
033
034
035    private static StorageWriter sw = new StorageWriter();
036
037    private static Appendable logAppendable = null;
038
039    static void setLogAppendable(Appendable lApp) { logAppendable = lApp; }
040
041    // Copies directly from the Upgrader.VERBOSE
042    private static boolean VERBOSE_PRINT_STEPS;
043
044    /** Please review the Java code-body to understand what this does. */
045    public static boolean isVerbose() { return VERBOSE_PRINT_STEPS; }
046
047    static void setVerbose(boolean VERBOSE_PRINT_STEPS)
048    { Messager.VERBOSE_PRINT_STEPS = VERBOSE_PRINT_STEPS; }
049
050    // MESSAGER: Throws JDE on Error, and sets both the fileName and processorName
051    static boolean checkPointLog()
052    {
053        String temp = C.toHTML(sw.getString(), true, true, true)
054            .replace("\t", "        ");
055
056        try
057        {
058            logAppendable.append(temp + "\n\n");
059            sw.erase();
060
061            return true;
062        }
063
064        catch (Exception e)
065        {
066            Messager.setProcessorName("Messager");
067            Messager.setCurrentFileName("User Provided Log", null);
068
069            Messager.assertFailGeneralPurpose(
070                e,
071                "Exception thrown while attempting to write to User-Provided Appendable-Log",
072                null
073            );
074
075            return false;
076        }
077    }
078
079
080    // ********************************************************************************************
081    // ********************************************************************************************
082    // Top Level Heading Dispatch
083    // ********************************************************************************************
084    // ********************************************************************************************
085
086
087    private static Integer indentation = 4;
088
089    private static String INDENT() { return (indentation==4) ? "    " : "        "; }
090
091    private static void printHeadingIfNecessary()
092    {
093        if (indentation == 4)       printFileHeadingIfNecessary();
094        else if (indentation == 8)  printDetailHeadingIfNecessary();
095        else                        throw new UnreachableError();
096        sw.println(INDENT() + "Processor [" + C.BCYAN + processorName + C.RESET + "]");
097    }
098
099
100    // ********************************************************************************************
101    // ********************************************************************************************
102    // HEADING-VALUES
103    // ********************************************************************************************
104    // ********************************************************************************************
105
106
107    private static String processorName = null;
108
109    static void setProcessorName(String processorName)
110    { Messager.processorName = processorName; }
111
112    // The "current" Java Doc HTML File being analyzed
113    private static String fileName = null;
114
115    private static String fileNameKind = null;
116
117    // The first time that an error or warning is printed, the detail-section location must be
118    // printed at the top of the message.  All subsequent messges do not need this error
119    // header message.
120
121    private static boolean printedFirstFileName = false;
122
123    static void setCurrentFileName(String fName, String fNameKind)
124    {
125        fileNameKind            = fNameKind;
126        fileName                = fName;
127        printedFirstFileName    = false;
128        indentation             = 4;
129        // Also clear the detail section
130        detailSection           = null;
131        printedFirstDetails     = false;
132    }
133
134    private static void printFileHeadingIfNecessary()
135    {
136        if (Messager.printedFirstFileName) return;
137
138        Messager.printedFirstFileName = true;
139
140        Messager.sw.println(
141            "Processing File: " +
142            "[" + C.BYELLOW + fileName + C.RESET + "]" +
143            ((fileNameKind != null) ? (", (" + fileNameKind + ")") : "") + ':'
144        );
145    }
146
147
148    // The "current" detail section about which error messages will be printed (if there are)
149    // any.
150
151    private static ReflHTML<?> detailSection = null;
152
153    // The "EmbedTag" processor treats the "TopDescription" as one of the details section.  It
154    // really isn't "a hack" - because the code is so long and the "Top Description" Embed Tag's
155    // are the exact same as the "Details" EmbedTag's.  This is also true for the "HiLiteDividers"
156
157    private static boolean topDescriptionAsDetails = false;
158
159    // The first time that an error or warning is printed, the detail-section location must be
160    // printed at the top of the message.  All subsequent messges do not need this error
161    // header message.
162
163    private static boolean printedFirstDetails = false;
164
165    static void setCurrentDetailSection(ReflHTML<?> detailSection)
166    {
167        Messager.detailSection              = detailSection;
168        Messager.printedFirstDetails        = false;
169        Messager.topDescriptionAsDetails    = false;
170        Messager.indentation                = 8;
171    }
172
173    static void setTopDescriptionSection()
174    {
175        Messager.detailSection              = null;
176        Messager.printedFirstDetails        = false;
177        Messager.topDescriptionAsDetails    = true;
178        Messager.indentation                = 8;
179    }
180
181    private static void printDetailHeadingIfNecessary()
182    {
183        printFileHeadingIfNecessary();
184
185        if (printedFirstDetails) return;
186
187        printedFirstDetails = true;
188
189        if (topDescriptionAsDetails)
190            sw.println
191                ("    Processing [" + C.BCYAN + "Main Type Description, at top" + C.RESET + "]");
192
193        else
194        {
195            // System.out.println("detailSection: " + detailSection);
196            // System.out.println("detailSection.entity: " + detailSection.entity);
197            String ln1 = (detailSection.entity.signatureLineNumber != -1)
198                ? ("Signature Line [" + C.BGREEN + detailSection.entity.signatureLineNumber +
199                    C.RESET + "]")
200                : null;
201
202            String ln2 = (detailSection.entity.jdStartLineNumber != -1)
203                ? ("JavaDoc Start Line [" + C.BGREEN + detailSection.entity.jdStartLineNumber +
204                    C.RESET + "]")
205                : null;
206
207            String line = "";
208
209            if (ln1 != null)        line = ln1 + ((ln2 != null) ? (", " + ln2) : "");
210            else if (ln2 != null)   line = ln2;
211
212            sw.println(
213                "    Processing " + C.BCYAN + detailSection.entityAsEnum.toString() + C.RESET +
214                    " Details Section " +
215                "for " + detailSection.entityAsEnum.toString() +
216                " [" + C.BRED + detailSection.entity.name + C.RESET + "], " +
217                line
218            );
219        }
220    }
221
222
223    // ********************************************************************************************
224    // ********************************************************************************************
225    // Counts
226    // ********************************************************************************************
227    // ********************************************************************************************
228
229
230    private static int errorCount   = 0;
231    private static int warningCount = 0;
232
233    static boolean hadErrors()  { return errorCount > 0;    }
234    static int numErrors()      { return errorCount;        }
235    static int numWarnings()    { return warningCount;      }
236
237    static int totalErrorsAndWarnings()
238    { return errorCount + warningCount; }
239
240    static boolean reachedMaxErrorsOrWarnings()
241    { return totalErrorsAndWarnings() > 25; }
242
243    public static boolean hadErrorsOrWarnings()
244    { return (errorCount > 0) || (warningCount > 0); }
245
246
247    // ********************************************************************************************
248    // ********************************************************************************************
249    // Cute Little Musings
250    // ********************************************************************************************
251    // ********************************************************************************************
252
253
254    public static void warning(String message)
255    {
256        warningCount++;
257        printHeadingIfNecessary();
258
259        sw.println(
260            INDENT() + "Warning: " +
261            StrIndent.indentAfter2ndLine(message, 4 + indentation, true, true)
262        );
263    }
264
265    public static void note(String message)
266    {
267        Messager.printHeadingIfNecessary();
268
269        sw.println(
270            INDENT() + "Note: " +
271            StrIndent.indentAfter2ndLine(message, 4 + indentation, true, true)
272        );
273    }
274
275
276    // ********************************************************************************************
277    // ********************************************************************************************
278    // MAIN-PRINTING
279    // ********************************************************************************************
280    // ********************************************************************************************
281
282
283    private static void ASSERT_FAIL(String oneLinerNote, String message, String signature)
284    {
285        errorCount++;
286        printHeadingIfNecessary();
287
288        signature = (signature != null)
289            ? ("Entity-Signature:\n" + StrIndent.indent((signature = signature.trim()), 4))
290            : "";
291
292        Messager.sw.println(
293            StrIndent.indent(
294                oneLinerNote +
295                StrIndent.indentAfter2ndLine(message.trim(), 4, true, true) + '\n' +
296                signature,
297                indentation
298            ));
299    }
300
301    private static void ASSERT_FAIL
302        (String oneLinerNote, Throwable t, String message, String signature)
303    {
304        errorCount++;
305        printHeadingIfNecessary();
306
307        signature = (signature != null)
308            ? ( "Entity-Signature:\n" + StrIndent.indent((signature=signature.trim()), 4) + '\n' +
309                "************************************************************************\n")
310            : "";
311
312        Messager.sw.println(
313            StrIndent.indent(
314                oneLinerNote + " (Exception Thrown)\n" +
315                "************************************************************************\n" +
316                EXCC.toString(t) + '\n' +
317                "************************************************************************\n" +
318                message + '\n' +
319                "************************************************************************\n" +
320                signature,
321                indentation
322            ));
323    }
324
325    private static void ERROR(Throwable t, String message, boolean FATAL, boolean showST)
326    {
327        errorCount++;
328        Messager.printHeadingIfNecessary();
329
330        Messager.sw.println(
331            StrIndent.indent(
332                (FATAL ? "Fatal Error: " : "Error: ") + "Exception Thrown:\n" +
333                "************************************************************************\n" +
334                (showST ? EXCC.toString(t) : ("Exception-Message: " + t.getMessage())) + '\n' +
335                "************************************************************************\n" +
336                message + '\n' +
337                "************************************************************************\n",
338                indentation
339            ));
340    }
341
342    private static void ERROR(String message, boolean FATAL)
343    {
344        errorCount++;
345        Messager.printHeadingIfNecessary();
346
347        Messager.sw.println(
348            INDENT() + (FATAL ? "Fatail Error: " : "Error: ") + 
349            StrIndent.indentAfter2ndLine(message, 4 + indentation, true, true)
350        );
351    }
352
353
354    // ********************************************************************************************
355    // ********************************************************************************************
356    // ASSERTS, Assert's have to be thought-of as **LIKELY** My-Fault
357    // ********************************************************************************************
358    // ********************************************************************************************
359
360
361    static <T> T assertFailCheckup(String message)
362    {
363        ASSERT_FAIL("Assertion-Checkup Error: ", message, null);
364        throw new JavaDocError();
365    }
366
367    static <T> T assertFailHTML(String message, String signature)
368    {
369        ASSERT_FAIL("Java-Doc HTML Parsing Error: ", message, signature);
370        throw new JavaDocHTMLParseException(message, signature);
371    }
372
373    static <T> T assertFailHTML(Throwable t, String message, String signature)
374    {
375        ASSERT_FAIL("Java-Doc HTML Parsing Error: ", t, message, signature);
376        throw new JavaDocHTMLParseException(message, t, signature);
377    }
378
379    static <T> T assertFailJavaParser(String message, String signature)
380    {
381        ASSERT_FAIL("Java-Parser Source-Code Parsing Error: ", message, signature);
382        throw new SourceCodeParseException(message, signature);
383    }
384
385    static <T> T assertFailJavaParser(Throwable t, String message, String signature)
386    {
387        ASSERT_FAIL("Java-Parser Source-Code Parsing Error: ", t, message, signature);
388        throw new SourceCodeParseException(message, t, signature);
389    }
390
391    static <T> T assertFailGeneralPurpose(String message, String signature)
392    {
393        ASSERT_FAIL("Java-Doc Upgrader Error: ", message, signature);
394        throw new UpgradeException();
395    }
396
397    static <T> T assertFailGeneralPurpose(Throwable t, String message, String signature)
398    {
399        ASSERT_FAIL("Java-Doc Upgrader Error: ", t, message, signature);
400        throw new UpgradeException();
401    }
402
403
404    // ********************************************************************************************
405    // ********************************************************************************************
406    // NON-ASSERT ERRORS, These are **LIKELY** Their-Fault (Not guaranteed anybody's fault)
407    // ********************************************************************************************
408    // ********************************************************************************************
409    //
410    // NOTE: These are all the exact same thing..
411
412
413    static <T> T  userErrorHalt(String message)
414    {
415        ERROR(message, true /* FATAL */);
416        throw new JavaDocError();
417    }
418
419    static <T> T userErrorHalt(Throwable t, String message)
420    {
421        ERROR(t, message, true /* FATAL */, true /* Show Stack-Trace */);
422        throw new JavaDocError();
423    }
424
425    static void userErrorContinue(String message)
426    { ERROR(message, false /* NON-FATAL */); }
427
428    static void userErrorContinue(Throwable t, String message)
429    { ERROR(t, message, false /* NON-FATAL */, false  /* Don't Show Stack-Trace */); }
430
431    static void errorExitingNow(Throwable t, String message)
432    { ERROR(t, message, true /* FATAL */, true  /* Show Stack-Trace */); }
433
434    static void errorExitingNow(String message)
435    { ERROR(message, true /* FATAL */); }
436
437    static void errorContinue(String message)
438    { ERROR(message, false /* NON-FATAL */); }
439
440    static void errorContinue(Throwable t, String message)
441    { ERROR(t, message, false /* NON-FATAL */, false  /* Don't Show Stack-Trace */); }
442
443
444    // ********************************************************************************************
445    // ********************************************************************************************
446    // Simple Printing
447    // ********************************************************************************************
448    // ********************************************************************************************
449
450
451    /**
452     * Prints input {@code 's'}
453     * @param s Any {@code java.lang.String}
454     */
455    public static void print(String s)
456    { sw.print(s); }
457
458    /**
459     * Prints input {@code 's'}, followed by a newline.
460     * @param s Any {@code java.lang.String}
461     */
462    public static void println(String s)
463    { sw.println(s); }
464
465    /** Prints a newline character */
466    public static void println()
467    { sw.println(); }
468
469    /**
470     * This prints a message to the parent-class {@link StorageWriter}, but only if the user has
471     * requested {@link Upgrade#VERBOSE_PRINT_STEPS}
472     * 
473     * <BR /><BR /><B>MINOR NOTE:</B> If the message being passed involves some complicated Java
474     * {@code StringBuilder}, it would be smarter &amp; more efficient, to only build that message
475     * after the {@code 'VERBOSE'} flag has been checked.  <I>Essentially, using this method is
476     * silly, if {@code 's'} has a bunch of {@code '+'} symbols before it is passed here.</I>
477     * 
478     * @param s The message to print to {@code StorageWriter} (the {@code Messager's} parent class)
479     */
480    public static void ifVPrintln(String s)
481    { if (VERBOSE_PRINT_STEPS) sw.println(s); }
482
483    /**
484     * This prints a message to the parent-class {@link StorageWriter}, but only if the user has
485     * requested {@link Upgrade#VERBOSE_PRINT_STEPS}
486     * 
487     * <BR /><BR /><B>MINOR NOTE:</B> If the message being passed involves some complicated Java
488     * {@code StringBuilder}, it would be smarter &amp; more efficient, to only build that message
489     * after the {@code 'VERBOSE'} flag has been checked.  <I>Essentially, using this method is
490     * silly, if {@code 's'} has a bunch of {@code '+'} symbols before it is passed here.</I>
491     * 
492     * @param s The message to print to {@code StorageWriter} (the {@code Messager's} parent class)
493     */
494    public static void ifVPrint(String s)
495    { if (VERBOSE_PRINT_STEPS) sw.print(s); }
496}