001package Torello.JavaDoc.Messager;
002
003import Torello.Java.StringParse;
004import Torello.Java.StrIndent;
005import Torello.Java.StrPrint;
006import Torello.Java.EXCC;
007
008import Torello.JavaDoc.ReflHTML;
009import Torello.JavaDoc.Declaration;
010
011import static Torello.Java.C.*;
012import static Torello.JavaDoc.Messager.Where_Am_I.LABEL_COLOR;
013
014import java.io.File;
015
016
017// This class exports two main methods named "ERROR".  These two methods are invoked by the
018// actual, "public", part of this Messager-Package.  The actual class "Messager" has quite a number
019// of "versions" of the two ERROR(...) Methods that are exported by this Package-Private class.
020// 
021// There is also a small "warning(...)" method that this class exports.  There is some likelihood
022// that this will be eliminated.  Early on it seemed like there could be the potential for many
023// User-Caused "Warning" Messages.  However, there really haven't been any, whatsoever.  That very
024// well could change with later code-reviews and bug-finding episodes.
025// 
026// NOT-SURE-YET !  For now, "warning(...)" will remain.
027// 
028// This entire class serves the primary purpose of "worrying about" all of the levels of
029// indentation that are needed to make the Error-Messages that the JDU generates actually look nice
030// and be readable.  The whole concept of printing the "Current Working File-Name and the "Current 
031// Working Processor Name" with proper indentation is accomplished by simply making note (by
032// updating a 'fileName' and 'Where_Am_I' internal / private field) whenever the JDU moves onto a
033// different file or a different HTML-Processor.
034// 
035// It sort of is "that simple".  The thing is that it is really difficult to make this "Messager
036// Package" look simple - even though it certainly is pretty simple.  Explaining what the JDU
037// Error-Reporting Code is expected to do is actually a little bit tricky.  I mean, all it really 
038// is doing is printing what would other-wise be an exception throw - to the screen, and then 
039// allowing Program Control-Flow to move onto the next thing that they do...
040// 
041// Sporadically, througout the JDU, there are checks which necessitate that if errors hae occurred
042// then the JDU-Tool must exit.  **FUNDAMENTALLY** - the entire purpose of a Messager-Class or 
043// Messager-Package is to print as many errors as possible to the user's terminal before exiting 
044// the application.  When debugging a project, the user simply cannot be bothered with restarting
045// his ugrader by, laboriousy, once for each and every "documentation bug" that exists in his 
046// upgrade configurations.
047// 
048// If the JDK's 'javac' command printed only 1 error when compiling many files, and then exited
049// unti each bug found had been eliminated - NOBODY WOULD USE JAVA, JAVAC OR THE JDK AT ALL because
050// it would be thought of as way too slow!
051// 
052// The Packages "JDUInternal.MainJDU" and "JDUInternal.Features" (along with other
053// classes/packages) are all expected to report to this Messager whenever they have begun
054// processing the next Java-Doc '.html' Web-Page, or begun using the next ReflHTML "Feature" 
055// Processor.
056// 
057// Again, all this Messager class really does is export Two "ERROR" printing methods and one 
058// "WARNIGN" printing method (which isn't even used right now, except in single location).  These
059// "Error Printers" do a verifiable "ton" of work to make sure the Error-Messages which are 
060// printed to the User's Terminal have great indentation, are properly wrapped if the text goes
061// on too long, and that all heading information for the errors are properly printed above the
062// messages.
063// 
064// The actual JDU Classes in this package all make calls to class 'Messager', rather than
065// 'MsgPkgPrivate'.
066
067/**
068 * This is an internally used class whose primary purpose is to generate the actual Java-Strings 
069 * which are printed to the User's Terminal on Error.
070 * 
071 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=PRINT_MESSAGE>
072 */
073public class PrintMessage
074{
075    // ********************************************************************************************
076    // ********************************************************************************************
077    // Constructor & Field
078    // ********************************************************************************************
079    // ********************************************************************************************
080
081
082    private final PrintRecord   printRecord;
083    private final PrintHeading  printHeading;
084
085    PrintMessage(final PrintRecord printRecord, final PrintHeading printHeading)
086    {
087        this.printRecord    = printRecord;
088        this.printHeading   = printHeading;
089    }
090
091
092    // ********************************************************************************************
093    // ********************************************************************************************
094    // Two, very simple, PRIVATE, Static-Fields
095    // ********************************************************************************************
096    // ********************************************************************************************
097
098
099    // This is used *ONCE* to print decide whether to print a particular stack-trace.
100    // It's the kind of thing that I really need, but the end user really shouldn't even expect
101    // to see it.
102
103    private static final boolean DEBUGGING = true;
104
105    private static final String BLUE_LINE =
106        BLUE_BKGND + BWHITE + StringParse.nChars('*', 70) + RESET + '\n';
107
108
109    // ********************************************************************************************
110    // ********************************************************************************************
111    // Two Main, Configurable, Error Message Printers
112    // ********************************************************************************************
113    // ********************************************************************************************
114
115
116    // Does not have a "Throwable"
117    void ERROR(
118            final String        message,
119            final String        signature,
120            final boolean       FATAL,
121            final Where_Am_I    WHERE_AM_I
122        )
123    {
124        final String oneLinerNote = null;
125
126        this.printRecord.incErrorCountAndCheck();
127
128        this.printHeading.printHeadingIfNecessary(WHERE_AM_I);
129
130
131        // In the lines below, String.trim() is used.  This is *ALWAYS* OK - unless the
132        // String being trimmed starts with a UNIX Color-Code Escape-Sequence.  The first character
133        // of a UNIX Escape Sequence is (synonymously named "ESCAPE") '\u001B'
134        //
135        // Java's String.trim() seems to be trimming that chacter!
136        // 
137        // However since "signature" and oneLinerNote are not supposed to have any Color-Codes in 
138        // them, it should not matter right here!
139
140        final String sigStr = (signature == null)
141            ? ""
142            : (
143                '\n' +
144                LABEL_COLOR + " Entity-Signature " + RESET + '\n' +
145                StrIndent.indent((signature.trim().replace("\t", "    ")), 4) + '\n'
146            );
147
148        final String firstLineNote =
149            ' ' +
150            (FATAL ? "Fatal " : "") +
151            ((oneLinerNote != null) ? oneLinerNote.trim() : "Error") +
152            ' ';
153
154        final int firstWrap = 100 - firstLineNote.length();
155
156        this.printRecord.sb
157            .append(
158                StrIndent.indent(
159                    LABEL_COLOR + firstLineNote + RESET +
160                    ' ' +
161                    StrIndent.indentAfter2ndLine(
162                        StrPrint.wrapToIndentationPlus(
163                            message
164                                .replaceAll("^[\\s]+|[\\s]+$", "") // Cannot use 'trim()'
165                                .replace("\t", "    "),
166                            firstWrap,
167                            100,
168                            4
169                        ),
170                        4,
171                        true,
172                        true
173                    ) +
174                    '\n' +
175                    sigStr,
176                    this.printRecord.getIndentation()
177                ))
178            .append('\n');
179    }
180
181    // Has Throwable **AND** 'showST'
182    void ERROR(
183            final Throwable     t,
184            final String        message,
185            final String        signature,
186            final boolean       FATAL,
187            final boolean       showST,
188            final Where_Am_I    WHERE_AM_I
189        )
190    {
191        final String oneLinerNote = null;
192
193        this.printRecord.incErrorCountAndCheck();
194
195        this.printHeading.printHeadingIfNecessary(WHERE_AM_I);
196
197        final String sigStr = (signature == null)
198            ? ""
199            : (
200                LABEL_COLOR + " Entity-Signature " + RESET + '\n' +
201                StrIndent.indent((signature.trim().replace("\t", "    ")), 4) + '\n' +
202                BLUE_LINE
203            );
204
205        final String topNote = (oneLinerNote != null)
206            ? (LABEL_COLOR + ' ' + oneLinerNote.trim() + ' ' + RESET + 
207                " (Exception Thrown)\n")
208            : (
209                LABEL_COLOR + ' ' +
210                (FATAL ? "Fatal " : "") +
211                "Error, Exception Thrown " + RESET + '\n'
212            );
213
214        final String exceptionStr = (FATAL || showST)
215            ? EXCC.toString(t)
216            : (
217                LABEL_COLOR + " Exception-Name " + RESET + "    " +
218                    BRED + t.getClass().getCanonicalName() +
219                    RESET +'\n' +
220                LABEL_COLOR + " Exception-Message " + RESET + ' ' +
221                    t.getMessage() + '\n' +
222                LABEL_COLOR + " Abbreviated-Trace " + RESET + ' ' +
223                    (DEBUGGING ? " (Debugging-Mode On, Abbreviation Off)" : "") +
224                    '\n' + 
225                    (DEBUGGING ? EXCC.toString(t, 4) : EXCC.toStringMaxTraces(t, 2, 4))
226            );
227
228
229        // String.trim() ==> It trims the UNIX Escape-Sequence Character '\u001B'
230        // It is not supposed to, acording to Chat-GPT !!  But it does anyway!
231        // 
232        // System.out.println(exceptionStr.trim());
233        // System.out.println(exceptionStr.replaceAll("^[\\s]+|[\\s]+$", ""));
234        // Torello.Java.Q.BP();
235
236        this.printRecord.sb
237            .append(
238                StrIndent.indent(
239                    StrPrint.wrapToIndentationPlus(
240                        topNote +
241                        BLUE_LINE +
242                        exceptionStr
243                            .replaceAll("^[\\s]+|[\\s]+$", "") // Cannot use 'trim()'
244                            .replace("\t", "    ") +
245                            '\n' +
246                        BLUE_LINE +
247                        message
248                            .replaceAll("^[\\s]+|[\\s]+$", "") // Cannot use 'trim()'
249                            .replace("\t", "    ") +
250                            '\n' +
251                        BLUE_LINE +
252                        sigStr,
253                        100,
254                        100,
255                        4
256                    ),
257                    this.printRecord.getIndentation()
258                ))
259            .append('\n');
260    }
261
262
263    // ********************************************************************************************
264    // ********************************************************************************************
265    // Warning
266    // ********************************************************************************************
267    // ********************************************************************************************
268
269
270    // Does not wahave a "Throwable"
271    void WARNING(
272            final String        message,
273            final Where_Am_I    WHERE_AM_I
274        )
275    {
276        this.printRecord.incWarningCount();
277
278        this.printHeading.printHeadingIfNecessary(WHERE_AM_I);
279
280        this.printRecord.sb
281            .append(
282                StrPrint.wrapToIndentationPlus(
283                    this.printRecord.getIndentationStr() + 
284                    LABEL_COLOR + " Warning " + RESET + ' ' +
285
286                    StrIndent.indentAfter2ndLine(
287                        message.replace("\t", "    "),
288                        4 + this.printRecord.getIndentation(),
289                        true,
290                        true
291                    ),
292                    100,
293                    100,
294                    4
295                ) +
296                '\n'
297            )
298            .append('\n');
299    }
300}