001package Torello.Java;
002
003import java.util.Vector;
004
005import Torello.JavaDoc.Annotations.LinkJavaSource;
006
007import java.util.HashMap;
008import java.io.File;
009
010/**
011 * A UNIX Terminal Color-Codes implementation for printing colored text to terminal.
012 * 
013 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=UNIX_COLORS>
014 */
015@Torello.JavaDoc.Annotations.StaticFunctional
016public class C
017{
018    private C() { }
019
020    /**
021     * If Java is not running on a UNIX machine, the terminal output that contains "color" will not function.
022     * If it does not, then the Shell color commands will default to empty, zero-length strings.
023     * 
024     * <BR /><BR /><B CLASS=JDDescLabel>WINDOWS SUPPORT:</B>
025     * 
026     * <BR />Since Windows Release 1909, which was the 2019 Version of Windows 10, MS-DOS Command
027     * Prompt Windows will also support ANSI Color-Code Escape Sequences;
028     */
029    public static final boolean colorANSI;
030
031    static
032    {
033        String  osName  = System.getProperty("os.name");
034        String  osArch  = System.getProperty("os.arch");
035        String  osVers  = System.getProperty("os.version");
036        boolean windows = StrCmpr.containsIgnoreCase(osName, "win");
037        boolean unix    = StrCmpr.containsOR_CI(osName, "nix", "nux", "aix");
038        float   version = -1;
039
040        if (windows)
041
042            try
043                { version = Float.parseFloat(osVers); }
044
045            catch (Exception e) { }
046
047        /*
048        // Finding out where this class works is more difficult than you realize
049        System.out.println(
050            "os.name:    " + osName + '\n' +
051            "os.arch:    " + osArch + '\n' +
052            "os.version: " + osVers + '\n' +
053            "version: "    + version
054        );
055        Q.BP();
056        */
057
058        if (windows)    colorANSI = (version >= 10);
059        else if (unix)  colorANSI = true;
060
061        else if (StrCmpr.containsIgnoreCase(osName, "max"))             colorANSI = false;
062        else if (StrCmpr.containsIgnoreCase(osName, "sunos"))           colorANSI = false;
063        else                                                            colorANSI = true;
064    }
065
066
067    public static final String RESET            = colorANSI ? "\u001B[0m"  : "";
068
069    public static final String BLACK            = colorANSI ? "\u001B[30m" : "";
070    public static final String RED              = colorANSI ? "\u001B[31m" : "";
071    public static final String GREEN            = colorANSI ? "\u001B[32m" : "";
072    public static final String YELLOW           = colorANSI ? "\u001B[33m" : "";
073    public static final String BLUE             = colorANSI ? "\u001B[34m" : "";
074    public static final String PURPLE           = colorANSI ? "\u001B[35m" : "";
075    public static final String CYAN             = colorANSI ? "\u001B[36m" : "";
076    public static final String WHITE            = colorANSI ? "\u001B[37m" : "";
077
078    public static final String BLACK_BKGND      = colorANSI ? "\u001B[40m" : "";
079    public static final String RED_BKGND        = colorANSI ? "\u001B[41m" : "";
080    public static final String GREEN_BKGND      = colorANSI ? "\u001B[42m" : "";
081    public static final String YELLOW_BKGND     = colorANSI ? "\u001B[43m" : "";
082    public static final String BLUE_BKGND       = colorANSI ? "\u001B[44m" : "";
083    public static final String PURPLE_BKGND     = colorANSI ? "\u001B[45m" : "";
084    public static final String CYAN_BKGND       = colorANSI ? "\u001B[46m" : "";
085    public static final String WHITE_BKGND      = colorANSI ? "\u001B[47m" : "";
086
087    public static final String BBLACK           = colorANSI ? "\u001B[90m" : "";
088    public static final String BRED             = colorANSI ? "\u001B[91m" : "";
089    public static final String BGREEN           = colorANSI ? "\u001B[92m" : "";
090    public static final String BYELLOW          = colorANSI ? "\u001B[93m" : "";
091    public static final String BBLUE            = colorANSI ? "\u001B[94m" : "";
092    public static final String BPURPLE          = colorANSI ? "\u001B[95m" : "";
093    public static final String BCYAN            = colorANSI ? "\u001B[96m" : "";
094    public static final String BWHITE           = colorANSI ? "\u001B[97m" : "";
095
096    public static final String BBLACK_BKGND     = colorANSI ? "\u001B[100m" : "";
097    public static final String BRED_BKGND       = colorANSI ? "\u001B[101m" : "";
098    public static final String BGREEN_BKGND     = colorANSI ? "\u001B[102m" : "";
099    public static final String BYELLOW_BKGND    = colorANSI ? "\u001B[103m" : "";
100    public static final String BBLUE_BKGND      = colorANSI ? "\u001B[104m" : "";
101    public static final String BPURPLE_BKGND    = colorANSI ? "\u001B[105m" : "";
102    public static final String BCYAN_BKGND      = colorANSI ? "\u001B[106m" : "";
103    public static final String BWHITE_BKGND     = colorANSI ? "\u001B[107m" : "";
104
105    private static final String CSS_DEFINITIONS_FILE =
106        "data-files" + File.separator + "C-CSS.sdat";
107
108    private static final String HTML_SPANS_FILE =
109        "data-files" + File.separator + "C-SPANS.sarrdat";
110
111    @SuppressWarnings("rawtypes")
112    private static final Vector v = LFEC.readObjectFromFile_JAR
113        (Torello.Java.C.class, HTML_SPANS_FILE, true, Vector.class);
114
115
116    // This list has:
117    // "</SPAN>" (Maps to: C.RESET)
118    // "<SPAN CLASS=SC1>" through SC8 (Maps to: C.BLACK ... C.WHITE)
119    // "<SPAN CLASS=SB1>" through SB8 (Maps to: C.BLACK_BKGND ... C.WHITE_BKGND)
120    // "<SPAN CLASS=BC1>" through BC8 (Maps to: C.BBLACK ... C.BWHITE)
121    // "<SPAN CLASS=BB1>" through BB8 (Maps to: C.BBLACK_BKGND ... C.BWHITE_BKGND)
122
123    @SuppressWarnings("unchecked")
124    static final String[] htmlSpansCSSClasses = (String[]) v.elementAt(0);
125
126
127    // This list is identical to the one above, but uses **INLINE** STYLE ATTRIBUTES:
128    // C.RESET          ==> "</SPAN>"
129    // C.BLACK          ==> "<SPAN style='color: black;'>"
130    // C.BLACK_BKGND    ==> "<SPAN style='background: black;'>"
131    // C.BBLACK         ==> "<SPAN style='color: black;  font-weight: bold;'>"
132    // C.BBLACK_BKGN    ==> "<SPAN style='background: brightblack;'>"
133
134    @SuppressWarnings("unchecked")
135    static final String[] htmlSpansStyleAttributes = (String[]) v.elementAt(1);
136
137
138    // Efficiently (using HashMap) converts a "Char Code String" to an array position
139    // The "Char Code String" may be any one of the 33 String defined in this class.
140    // The array position is an index into the PREVIOUS TWO ARRAYS.
141
142    @SuppressWarnings("unchecked")
143    private static final HashMap<String, Integer> charCodesMap =
144        (HashMap<String, Integer>) v.elementAt(2);
145
146
147    // less efficient version, 'StrRepace' requires this...  Note - these Strings are all
148    // extremely short.  There isn't a way to improve StrReplace in this regard - it *MUST*
149    // check for *ALL* of the codes...
150    // 
151    // This is used inside one of the Package-Private Helper Classes
152    // Specifically: TextToHTML
153
154    static final String[] charCodesArr = (String[]) v.elementAt(3);
155
156
157    /**
158     * This will convert a UNIX 'Character Code' into an HTML Tag if it is necessary to convert
159     * UNIX colored-text into HTML.
160     * 
161     * <BR /><BR /><B CLASS=JDDescLabel>CSS-Definitions:</B>
162     * 
163     * <BR />This method returns an HTML {@code SPAN}-Tag that contains an inline 
164     * {@code CSS-CLASS}.  It is (hopefully) obvious that the definitiions for any / all
165     * {@code CSS-CLASSES} that are used will need to be provided on the page.
166     * 
167     * <BR /><BR />The method {@link #getCSSDefinitions()} will return the complete definition
168     * page for all {@code CSS CLASSES} that are employed by this method.
169     * 
170     * <BR /><BR />You may also view the contents of the CSS Definitions Below:
171     * 
172     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
173     * 
174     * @param charCode Any one of the 33 codes defined in this class.
175     * 
176     * @return An HTML {@code <SPAN CLASS=...>} element that may be used as a substitute for
177     * one of the codes defined in this class.
178     * 
179     * @throws IllegalArgumentException If the {@code String} that is passed to parameter
180     * {@code 'charCode'} is not one of the defined codes in this class.
181     * 
182     * @see #getCSSDefinitions()
183     */
184    public static String span(String charCode)
185    {
186        final Integer arrPos = charCodesMap.get(charCode);
187
188        if (arrPos == null) throw new IllegalArgumentException(
189            "The value passed to parameter 'charCode' is not one of the defined codes in " +
190            "this class."
191        );
192
193        return htmlSpansCSSClasses[arrPos];
194    }
195
196    /**
197     * This will convert a UNIX 'Character Code' into an HTML Tag if it is necessary to convert
198     * UNIX colored-text into HTML.
199     * 
200     * <BR /><BR /><B CLASS=JDDescLabel>CSS Inline-Style:</B>
201     *
202     * <BR />This method returns an HTML {@code SPAN}-Tag that contains an <B>inline
203     * {@code STYLE}-Attribute</B>.  Remember, if you are converting large Text-{@code String's}
204     * into HTML using inlne {@code STYLE}-Attributes, your output could potentially grow very
205     * large, and rather quickly.
206     * 
207     * <BR /><BR />Using {@code CSS-CLASSES} provided by method {@link #span(java.lang.String)}
208     * <I>will make your generated HTML <B>somewhat</B> more efficient</I>.  If you do, you must
209     * remember to import the CSS Definitions for these classes somewhere in your HTML-File.
210     * 
211     * @param charCode Any one of the 33 codes defined in this class.
212     * 
213     * @return An HTML {@code <SPAN STYLE=...>} element that may be used as a substitute for
214     * one of the color-codes defined in this class.
215     * 
216     * @throws IllegalArgumentException If the {@code String} that is passed to parameter
217     * {@code 'charCode'} is not one of the defined codes in this class.
218     */
219    public static String spanInlineStyle(String charCode)
220    {
221        final Integer arrPos = charCodesMap.get(charCode);
222
223        if (arrPos == null) throw new IllegalArgumentException(
224            "The value passed to parameter 'charCode' is not one of the defined codes in " +
225            "this class."
226        );
227
228        return htmlSpansStyleAttributes[arrPos];
229    }
230
231    /**
232     * Convenience Method.
233     * <BR />Invokes: {@link #toHTML(String, boolean, boolean, boolean)}
234     */
235    public static String toHTML(String text) { return toHTML(text, false, true, false); }
236
237
238    /**
239     * Converts the instances of these escape-sequences that are found inside of Java
240     * {@code String's} that were generated using these ANSI UNIX color escape sequences, and
241     * produces a valid HTML {@code String} that contains HTML
242     * {@code <SPAN STYLE="color-information">} replacements!
243     *
244     * <BR /><BR /><B CLASS=JDDescLabel>New-Line Characters:</B>
245     *
246     * <BR />Any new-line Character-Sequences such as {@code '\n'} or {@code '\r\n'} will be
247     * replaced with HTML {@code <BR />} elements.
248     * 
249     * @param text This should be any string, usually one that is saved from a
250     * {@code 'StorageWriter'}, although any text that includes these UNIX Color Escape Codes
251     * is fine.
252     * 
253     * @param preFormat When this parameter receives {@code FALSE}, everywhere in the input
254     * text-{@code String} that a {@code CRLF} (new-line) occurs, that newline will be replaced
255     * by an HTML {@code <BR />} element, in addition to the original newline.
256     * 
257     * <BR /><BR />This parameter is referring to the CSS {@code 'white-space: pre'} setting,
258     * which can be used.  Althought, sometimes going with the plain-old-vanilla {@code <BR />}
259     * tag can also be advisable.
260     * 
261     * @param escapeHTMLElements Whenever HTML is sent to the input-parameter 'text' - if the
262     * intention is to render the HTML using the browser, this parameter should be
263     * {@code FALSE}.  If it is intended to allow the UI to "show the HTML" like it were
264     * text-to-be-viewed, then each and every greater-than-symbol {@code '>'} and also every
265     * less-than-symbol {@code '<'} will be escaped.  This is done to prevent the browser from
266     * trying to parse the text as HTML.
267     * 
268     * @param useCSSClasses When this parameter receives {@code TRUE}, all returned
269     * {@code <SPAN STYLE=...>} elements shall be converted to using a simplified
270     * {@code CSS Class Name}.  The {@code CLASS} definitions for the returned {@code String}
271     * can be retrieved by simply calling the method: {@link #getCSSDefinitions()}.
272     * 
273     * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT:</SPAN></B> If this parameter does
274     * receive a {@code TRUE} value, it is imperitive to include the {@code CSS STYLE}
275     * definitions that are returned by the above mentioned method, or else the colors shall
276     * not be visible.
277     * 
278     * <BR /><BR />You may view the contents of the CSS Definitions Below:
279     * 
280     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
281     * 
282     * @return Every UNIX-ANSI color escape-sequence that is found/identified in this text will
283     * be replaced with an HTML
284     * {@code <SPAN STYLE="color: a-color; background: a-background-color">} element.
285     */ 
286    @LinkJavaSource(handle="TextToHTML")
287    public static String toHTML(
288            final String    text,
289            final boolean   preFormat,
290            final boolean   escapeHTMLElements,
291            final boolean   useCSSClasses
292        )
293    { return TextToHTML.convert(text, preFormat, escapeHTMLElements, useCSSClasses); }
294
295    /**
296     * If the {@code 'useCSSDefinitions'} option is selected with the
297     * {@link #toHTML(String, boolean, boolean, boolean)} method, then the {@code String}
298     * returned from this method shall provide the {@code CSS Style} definitions needed to use
299     * the colors provided by {@code toHTML(...)}
300     * 
301     * @return This shall visit the internal data-files for this JAR distribution, and return a
302     * list of {@code CSS Style} definitions that will colorize the HTML produced by an
303     * invocation of {@code toHTML()}.
304     * 
305     * <BR /><BR />You may view the contents of the CSS Definitions Below:
306     * 
307     * <BR /><BR /><B><A HREF="hilite-files/C.css.html">Shell.C CSS Definitions</A></B>
308     */
309    public static String getCSSDefinitions()
310    {
311        /*
312        return LFEC.readObjectFromFile_JAR
313            (Torello.Data.DataFileLoader.class, CSS_DEFINITIONS_FILE, true, String.class);
314        */
315
316        return LFEC.readObjectFromFile_JAR
317            (Torello.Java.C.class, CSS_DEFINITIONS_FILE, true, String.class);
318    }
319
320    /**
321     * Convenience Method.
322     * <BR />Creates an {@code '.html'}-file from the output produced by
323     * {@link #toHTML(String, boolean, boolean, boolean)}
324     * <BR />Invokes: {@link #getCSSDefinitions()}
325     * <BR />And Invokes: {@link #toHTML(String, boolean, boolean, boolean)}
326     * <BR />Passes: {@code TRUE} to parameter {@code 'preFormat'}
327     * <BR />Passes: {@code TRUE} to parameter {@code 'escapeHTMLElements'}
328     * <BR />Passes: {@code TRUE} to parameter {@code 'useCSSClasses'}
329     */
330    @LinkJavaSource(handle="TextToHTMLPage")
331    public static String toHTML(String text, String titleStr)
332    { return TextToHTMLPage.convert(text, titleStr); }
333}