1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
package Torello.Java;

import java.util.Vector;
import java.util.HashMap;
import java.io.File;

/**
 * A UNIX Terminal Color-Codes implementation for printing colored text to terminal.
 * 
 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=UNIX_COLORS>
 */
@Torello.JavaDoc.StaticFunctional
public class C
{
    private C() { }

    /**
     * If Java is not running on a UNIX machine, the terminal output that contains "color" will not function.
     * If it does not, then the Shell color commands will default to empty, zero-length strings.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>WINDOWS SUPPORT:</B>
     * 
     * <BR />Since Windows Release 1909, which was the 2019 Version of Windows 10, MS-DOS Command
     * Prompt Windows will also support ANSI Color-Code Escape Sequences;
     */
    public static final boolean colorANSI;

    static
    {
        String  osName  = System.getProperty("os.name");
        String  osArch  = System.getProperty("os.arch");
        String  osVers  = System.getProperty("os.version");
        boolean windows = StrCmpr.containsIgnoreCase(osName, "win");
        boolean unix    = StrCmpr.containsOR_CI(osName, "nix", "nux", "aix");
        float   version = -1;

        if (windows)

            try
                { version = Float.parseFloat(osVers); }

            catch (Exception e) { }

        /*
        // Finding out where this class works is more difficult than you realize
        System.out.println(
            "os.name:    " + osName + '\n' +
            "os.arch:    " + osArch + '\n' +
            "os.version: " + osVers + '\n' +
            "version: "    + version
        );
        Q.BP();
        */

        if (windows)    colorANSI = (version >= 10);
        else if (unix)  colorANSI = true;

        else if (StrCmpr.containsIgnoreCase(osName, "max"))             colorANSI = false;
        else if (StrCmpr.containsIgnoreCase(osName, "sunos"))           colorANSI = false;
        else                                                            colorANSI = true;
    }


    public static final String RESET            = colorANSI ? "\u001B[0m"  : "";

    public static final String BLACK            = colorANSI ? "\u001B[30m" : "";
    public static final String RED              = colorANSI ? "\u001B[31m" : "";
    public static final String GREEN            = colorANSI ? "\u001B[32m" : "";
    public static final String YELLOW           = colorANSI ? "\u001B[33m" : "";
    public static final String BLUE             = colorANSI ? "\u001B[34m" : "";
    public static final String PURPLE           = colorANSI ? "\u001B[35m" : "";
    public static final String CYAN             = colorANSI ? "\u001B[36m" : "";
    public static final String WHITE            = colorANSI ? "\u001B[37m" : "";

    public static final String BLACK_BKGND      = colorANSI ? "\u001B[40m" : "";
    public static final String RED_BKGND        = colorANSI ? "\u001B[41m" : "";
    public static final String GREEN_BKGND      = colorANSI ? "\u001B[42m" : "";
    public static final String YELLOW_BKGND     = colorANSI ? "\u001B[43m" : "";
    public static final String BLUE_BKGND       = colorANSI ? "\u001B[44m" : "";
    public static final String PURPLE_BKGND     = colorANSI ? "\u001B[45m" : "";
    public static final String CYAN_BKGND       = colorANSI ? "\u001B[46m" : "";
    public static final String WHITE_BKGND      = colorANSI ? "\u001B[47m" : "";

    public static final String BBLACK           = colorANSI ? "\u001B[90m" : "";
    public static final String BRED             = colorANSI ? "\u001B[91m" : "";
    public static final String BGREEN           = colorANSI ? "\u001B[92m" : "";
    public static final String BYELLOW          = colorANSI ? "\u001B[93m" : "";
    public static final String BBLUE            = colorANSI ? "\u001B[94m" : "";
    public static final String BPURPLE          = colorANSI ? "\u001B[95m" : "";
    public static final String BCYAN            = colorANSI ? "\u001B[96m" : "";
    public static final String BWHITE           = colorANSI ? "\u001B[97m" : "";

    public static final String BBLACK_BKGND     = colorANSI ? "\u001B[100m" : "";
    public static final String BRED_BKGND       = colorANSI ? "\u001B[101m" : "";
    public static final String BGREEN_BKGND     = colorANSI ? "\u001B[102m" : "";
    public static final String BYELLOW_BKGND    = colorANSI ? "\u001B[103m" : "";
    public static final String BBLUE_BKGND      = colorANSI ? "\u001B[104m" : "";
    public static final String BPURPLE_BKGND    = colorANSI ? "\u001B[105m" : "";
    public static final String BCYAN_BKGND      = colorANSI ? "\u001B[106m" : "";
    public static final String BWHITE_BKGND     = colorANSI ? "\u001B[107m" : "";

    private static final String CSS_DEFINITIONS_FILE =
        "data-files" + File.separator + "C-CSS.sdat";

    private static final String HTML_SPANS_FILE =
        "data-files" + File.separator + "C-SPANS.sarrdat";

    @SuppressWarnings("rawtypes")
    private static final Vector v = LFEC.readObjectFromFile_JAR
        (Torello.Java.C.class, HTML_SPANS_FILE, true, Vector.class);


    // This list has:
    // "</SPAN>" (Maps to: C.RESET)
    // "<SPAN CLASS=SC1>" through SC8 (Maps to: C.BLACK ... C.WHITE)
    // "<SPAN CLASS=SB1>" through SB8 (Maps to: C.BLACK_BKGND ... C.WHITE_BKGND)
    // "<SPAN CLASS=BC1>" through BC8 (Maps to: C.BBLACK ... C.BWHITE)
    // "<SPAN CLASS=BB1>" through BB8 (Maps to: C.BBLACK_BKGND ... C.BWHITE_BKGND)

    @SuppressWarnings("unchecked")
    private static final String[] htmlSpansCSSClasses = (String[]) v.elementAt(0);

    // This list is identical to the one above, but uses **INLINE** STYLE ATTRIBUTES:
    // C.RESET          ==> "</SPAN>"
    // C.BLACK          ==> "<SPAN style='color: black;'>"
    // C.BLACK_BKGND    ==> "<SPAN style='background: black;'>"
    // C.BBLACK         ==> "<SPAN style='color: black;  font-weight: bold;'>"
    // C.BBLACK_BKGN    ==> "<SPAN style='background: brightblack;'>"

    @SuppressWarnings("unchecked")
    private static final String[] htmlSpansStyleAttributes = (String[]) v.elementAt(1);

    // Efficiently (using HashMap) converts a "Char Code String" to an array position
    // The "Char Code String" may be any one of the 33 String defined in this class.
    // The array position is an index into the PREVIOUS TWO ARRAYS.

    @SuppressWarnings("unchecked")
    private static final HashMap<String, Integer> charCodesMap =
        (HashMap<String, Integer>) v.elementAt(2);

    // less efficient version, 'StrRepace' requires this...  Note - these Strings are all
    // extremely short.  There isn't a way to improve StrReplace in this regard - it *MUST*
    // check for *ALL* of the codes...

    private static final String[] charCodesArr = (String[]) v.elementAt(3);


    /**
     * This will convert a UNIX 'Character Code' into an HTML Tag if it is necessary to convert
     * UNIX colored-text into HTML.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>CSS-Definitions:</B>
     * 
     * <BR />This method returns an HTML {@code SPAN}-Tag that contains an inline 
     * {@code CSS-CLASS}.  It is (hopefully) obvious that the definitiions for any / all
     * {@code CSS-CLASSES} that are used will need to be provided on the page.
     * 
     * <BR /><BR />The method {@link #getCSSDefinitions()} will return the complete definition
     * page for all {@code CSS CLASSES} that are employed by this method.
     * 
     * <BR /><BR />You may also view the contents of the CSS Definitions Below:
     * 
     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
     * 
     * @param charCode Any one of the 33 codes defined in this class.
     * 
     * @return An HTML {@code <SPAN CLASS=...>} element that may be used as a substitute for
     * one of the codes defined in this class.
     * 
     * @throws IllegalArgumentException If the {@code String} that is passed to parameter
     * {@code 'charCode'} is not one of the defined codes in this class.
     * 
     * @see #getCSSDefinitions()
     */
    public static String span(String charCode)
    {
        Integer arrPos = charCodesMap.get(charCode);

        if (arrPos == null) throw new IllegalArgumentException(
            "The value passed to parameter 'charCode' is not one of the defined codes in " +
            "this class."
        );

        return htmlSpansCSSClasses[arrPos];
    }

    /**
     * This will convert a UNIX 'Character Code' into an HTML Tag if it is necessary to convert
     * UNIX colored-text into HTML.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>CSS Inline-Style:</B>
     *
     * <BR />This method returns an HTML {@code SPAN}-Tag that contains an <B>inline
     * {@code STYLE}-Attribute</B>.  Remember, if you are converting large Text-{@code String's}
     * into HTML using inlne {@code STYLE}-Attributes, your output could potentially grow very
     * large, and rather quickly.
     * 
     * <BR /><BR />Using {@code CSS-CLASSES} provided by method {@link #span(java.lang.String)}
     * <I>will make your generated HTML <B>somewhat</B> more efficient</I>.  If you do, you must
     * remember to import the CSS Definitions for these classes somewhere in your HTML-File.
     * 
     * @param charCode Any one of the 33 codes defined in this class.
     * 
     * @return An HTML {@code <SPAN STYLE=...>} element that may be used as a substitute for
     * one of the color-codes defined in this class.
     * 
     * @throws IllegalArgumentException If the {@code String} that is passed to parameter
     * {@code 'charCode'} is not one of the defined codes in this class.
     */
    public static String spanInlineStyle(String charCode)
    {
        Integer arrPos = charCodesMap.get(charCode);

        if (arrPos == null) throw new IllegalArgumentException(
            "The value passed to parameter 'charCode' is not one of the defined codes in " +
            "this class."
        );

        return htmlSpansStyleAttributes[arrPos];
    }

    /**
     * Convenience Method.
     * <BR />Invokes: {@link #toHTML(String, boolean, boolean, boolean)}
     */
    public static String toHTML(String text) { return toHTML(text, false, true, false); }

    // Used in method below
    private static final String[] MATCH_STRS_1 = { "<", ">", "\n\r", "\r\n", "\n", "\r" };
    private static final String[] MATCH_STRS_2 = { "<", ">" };
    private static final String[] MATCH_STRS_3 = { "\n\r", "\r\n", "\n", "\r" };

    private static final String REPLACER(int i, String s)
    {
        switch (s)
        {
            case "<" : return "&lt;";
            case ">" : return "&gt;";
            case "\n" :
            case "\r" :
            case "\n\r" : 
            case "\r\n" : return "<BR />\n";
            default: throw new UnreachableError();
        }
    }

    /**
     * Converts the instances of these escape-sequences that are found inside of Java
     * {@code String's} that were generated using these ANSI UNIX color escape sequences, and
     * produces a valid HTML {@code String} that contains HTML
     * {@code <SPAN STYLE="color-information">} replacements!
     *
     * <BR /><BR /><B CLASS=JDDescLabel>New-Line Characters:</B>
     *
     * <BR />Any new-line Character-Sequences such as {@code '\n'} or {@code '\r\n'} will be
     * replaced with HTML {@code <BR />} elements.
     * 
     * @param text This should be any string, usually one that is saved from a
     * {@code 'StorageWriter'}, although any text that includes these UNIX Color Escape Codes
     * is fine.
     * 
     * @param preFormat When this parameter receives {@code FALSE}, everywhere in the input
     * text-{@code String} that a {@code CRLF} (new-line) occurs, that newline will be replaced
     * by an HTML {@code <BR />} element, in addition to the original newline.
     * 
     * <BR /><BR />This parameter is referring to the CSS {@code 'white-space: pre'} setting,
     * which can be used.  Althought, sometimes going with the plain-old-vanilla {@code <BR />}
     * tag can also be advisable.
     * 
     * @param escapeHTMLElements Whenever HTML is sent to the input-parameter 'text' - if the
     * intention is to render the HTML using the browser, this parameter should be
     * {@code FALSE}.  If it is intended to allow the UI to "show the HTML" like it were
     * text-to-be-viewed, then each and every greater-than-symbol {@code '>'} and also every
     * less-than-symbol {@code '<'} will be escaped.  This is done to prevent the browser from
     * trying to parse the text as HTML.
     * 
     * @param useCSSClasses When this parameter receives {@code TRUE}, all returned
     * {@code <SPAN STYLE=...>} elements shall be converted to using a simplified
     * {@code CSS Class Name}.  The {@code CLASS} definitions for the returned {@code String}
     * can be retrieved by simply calling the method: {@link #getCSSDefinitions()}.
     * 
     * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT:</SPAN></B> If this parameter does
     * receive a {@code TRUE} value, it is imperitive to include the {@code CSS STYLE}
     * definitions that are returned by the above mentioned method, or else the colors shall
     * not be visible.
     * 
     * <BR /><BR />You may view the contents of the CSS Definitions Below:
     * 
     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
     * 
     * @return Every UNIX-ANSI color escape-sequence that is found/identified in this text will
     * be replaced with an HTML
     * {@code <SPAN STYLE="color: a-color; background: a-background-color">} element.
     */ 
    public static String toHTML
        (String text, boolean preFormat, boolean escapeHTMLElements, boolean useCSSClasses)
    {
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        // Old Way, much less efficient
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

        // If the input text, itself, has HTML elements, then those have to be "escaped" to
        // properly render.  If the intention was to have them rendered has HTML Elements
        // (not text), then this boolean should be false.

        // if (escapeHTMLElements) text = text.replace("<", "&lt;").replace(">", "&gt;");

        // With "Pre-Formatted Text" - there is no need to add "<BR />" where line-breaks
        // occur CRLF will automatically be inserted courtesy of the browser

        // if (! preFormat) text = text.replaceAll("\n|\r\n|\r", "<BR />\n");


        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        // Quite a bit faster
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

        String[] matchStrs = null;

        // Replaces both '<', '>' **AND** '\n', '\r', '\n\r', '\r\n' (all at once)
        if (escapeHTMLElements && (! preFormat))            matchStrs = MATCH_STRS_1;

        // Replaces ONLY '<' and '>'
        else if (escapeHTMLElements && preFormat)           matchStrs = MATCH_STRS_2;

        // Replaces ONLY '\n', '\r', '\n\r', '\r\n'
        else if ((! escapeHTMLElements) && (! preFormat))   matchStrs = MATCH_STRS_3;

        // NOW RUN IT...
        if (matchStrs != null) text = StrReplace.r(text, matchStrs, C::REPLACER);

        return StrReplace.r(
            text, charCodesArr, 
            useCSSClasses ? htmlSpansCSSClasses : htmlSpansStyleAttributes
        );
    }

    /**
     * If the {@code 'useCSSDefinitions'} option is selected with the
     * {@link #toHTML(String, boolean, boolean, boolean)} method, then the {@code String}
     * returned from this method shall provide the {@code CSS Style} definitions needed to use
     * the colors provided by {@code toHTML(...)}
     * 
     * @return This shall visit the internal data-files for this JAR distribution, and return a
     * list of {@code CSS Style} definitions that will colorize the HTML produced by an
     * invocation of {@code toHTML()}.
     * 
     * <BR /><BR />You may view the contents of the CSS Definitions Below:
     * 
     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
     */
    public static String getCSSDefinitions()
    {
        /*
        return LFEC.readObjectFromFile_JAR
            (Torello.Data.DataFileLoader.class, CSS_DEFINITIONS_FILE, true, String.class);
        */

        return LFEC.readObjectFromFile_JAR
            (Torello.Java.C.class, CSS_DEFINITIONS_FILE, true, String.class);
    }

    /**
     * Convenience Method.
     * <BR />Creates an {@code '.html'}-file from the output produced by
     * {@link #toHTML(String, boolean, boolean, boolean)}
     * <BR />Invokes: {@link #getCSSDefinitions()}
     * <BR />And Invokes: {@link #toHTML(String, boolean, boolean, boolean)}
     * <BR />Passes: {@code TRUE} to parameter {@code 'useCSSClasses'}
     */
    public static String toHTML
        (String text, boolean preFormat, boolean escapeHTMLElements, String titleStr)
    {
        return
            "<HTML>\n" +
            "<HEAD>\n" +
            "<TITLE>" + titleStr + "</TITLE>\n" +
            "<STYLE TYPE='text/css'>\n" + '\n' +

            // This method simply copies the CSS-Definitions File out of the Java-HTML JAR, and
            // into a String that is returned to the user.  Make sure to wrap that String
            // inside of a <STYLE>...</STYLE> HTML-Tag.  Also - set the background color

            getCSSDefinitions() +

            "BODY { background: black; color: white; }\n" +
            "</STYLE>\n" +
            "</HEAD>\n" +
            "<BODY>\n" +
            (preFormat ? "<PRE>\n" : "") +

            // NOTE: This just calls the other variant of 'toHTML' - but ensures that 'true' is
            // passed to the 'useCSSClasses' parameter.

            toHTML(text, preFormat, escapeHTMLElements, true) + 

            (preFormat ? "</PRE>\n" : "") +
            "</BODY>\n" +
            "</HTML>";
    }
}