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
package Torello.Java.Build;

import Torello.Java.FileTransfer;
import Torello.Java.FileNode;
import Torello.Java.StringParse;
import Torello.Java.RTC;

import Torello.Java.ReadOnly.ReadOnlyList;
import Torello.Java.ReadOnly.ReadOnlyArrayList;

import static Torello.Java.C.BGREEN_BKGND;
import static Torello.Java.C.BRED_BKGND;
import static Torello.Java.C.BCYAN;
import static Torello.Java.C.BGREEN;
import static Torello.Java.C.BYELLOW;
import static Torello.Java.C.RESET;

import java.io.File;
import java.io.IOException;

import java.util.Map;
import java.util.TreeMap;

/**
 * The purpose of a Build-Tool is, fundamentally, to make a project possible by doing what a
 * programmer would otherwise need enter manually into a keyboard hundreds of thousands of times
 * himself.  The package {@lnk Torello.Java.Build} provides a CLI Menu that would performs hundreds
 * and hundreds of otherwise <B STYLE='color: red;'><I>extremely trivial tasks</I></B> via a single 
 * UNIX CLI Command.
 * 
 * <BR /><BR />It is likely that no programmer on earth would determine that running the Standard
 * Java Command <B>{@code 'javac'}</B> at a UNIX prompt to be an overly cumbersome or difficult
 * task.  Building and re-building the Data-Files for a particular project requires just that: 
 * compiling some {@code '.java'} files, and then executing their {@code '.class'} Files in order 
 * to obtain their output.  Everything seems quite trivial so far.
 * 
 * <BR /><BR />Things become difficult when a project (for example the Java-HTML Library Tool) has 
 * such Data-File Building {@code '.java'} classes spread out across quite a number of 
 * <B STYLE='color:red;'>{@code ../data-files/}</B> directories, and furthermore each of those
 * directories have multiple Data-Files Classes to both compile and build.  In such cases, whenever
 * the need arises to tweak, debug, update or add to the
 * <B STYLE='color:red;'>{@code ../data-files/}</B> directories, the value of some sort of 
 * scripting tool starts to look like an invaluable tool in the programmer's arsenal.
 * 
 * <BR /><BR />Why?
 * 
 * <BR /><BR />Because typing:
 * 
 * <BR /><BR /><OL CLASS=JDOL>
 * <LI>{@code 'cd <dir-name>'} and</LI>
 * <LI>{@code 'javac -switches <java-files>'} and</LI>
 * <LI>{@code 'java <class-files>'}</LI>
 * </OL>
 * 
 * <BR /><BR >over and over again is a ROYAL PAIN IN THE ASS.
 * 
 * <BR /><BR />That's what this tool does for you.  It enters all {@code '../data-files/'}
 * sub-directories of all Package Source Directories in your project and compiles then.
 * Afterwards, it invokes the <B>{@link DataFileBuilderClass#build(String) build}</B> Method on
 * any {@code '.class'} files which have implemented the <B>{@link DataFileBuilderClass}</B>
 * inteface.
 * 
 * <BR /><BR /><UL CLASS=JDUL>
 * 
 * <LI> Enter all <B STYLE='color:red;'>{@code my/package/dir/data-files/}</B> directories
 *      <BR ><BR />
 *      </LI>
 * 
 * <LI> Wipe / Delete all Java {@code '.class'}-Files present in {@code ../data-files/} and its
 *      sub-directories.
 *      <BR /><BR />
 *      </LI>
 * 
 * <LI> Invoke {@code 'javac'} (Re-Compile) all {@code '.java'}-Files present in the directory and
 *      its sub-directories.
 *      <BR /><BR />
 *      </LI>
 * 
 * <LI> Scan {@code ../data-files/} and its sub directories for any and all {@code '.class'}-Files.
 *      Afterwards, seek and identify if any of them implement the
 *      {@link DataFileBuilderClass} interface.
 *      <BR /><BR />
 *      </LI>
 * 
 * <LI> Invoke the {@link DataFileBuilderClass#build(String)} method on those classes which do 
 *      implement the aforementioned interface.  If the user has properly written them, those 
 *      classes will produce Data-Files which are needed and required for the particular
 *      Java-Package being examined.
 *      <BR /><BR />
 *      </LI>
 * 
 * <LI> That's all folks!  It is that simple... 😊😊😊</LI>
 * </UL>
 * 
 * <BR /><BR /><B CLASS=JDDescLabel>CLI Output Example:</B>
 * 
 * <BR />The following {@code '.html'}-Page demonstrates what the output looks like when running
 * this class against all of the <B STYLE='color: red;'>{@code '../data-files/'}</B> directries
 * which are utilized by this Java-HTML JAR-Library.  This output was generated by this tool on
 * Janaury 6th, 2025.
 * 
 * <BR /><BR /><B><CODE><A HREF='doc-files/Data-File-Builder.Output.html'>
 * Data-File-Builder.Output.html</A></CODE></B>
 */ 
public class BuildDataFiles
{
    private BuildDataFiles() { }

    /**
     * This method should be invoked by any {@code public static void main} method, and pass 
     * <B STYLE='color: red;'><I>BOTH</I></B> the provided {@code 'String[] argv'} parameter to 
     * this method, <B STYLE='color: red;'><I>AND</I></B> the remained of the required parameters
     * needed.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>Helper Code:</B>
     * 
     * <BR />This method invokes two Package-Private and Internal-Classes for help.  These external
     * classes are listed above, at the top of this class' documentation page, and also here, below:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * 
     * <LI> <B><A HREF='hilite-files/CompileDataFilesBuilders.java.html'>
     *      CompileDataFilesBuilders.java</A></B></LI>
     * 
     * <LI> <B><A HREF='hilite-files/RunDataFilesBuilders.java.html'>
     *      RunDataFilesBuilders.java</A></B></LI>
     * 
     * </UL>
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>Example &amp; Output:</B>
     * 
     * <BR />This class &amp; method are, indeed, utilized by the Java-HTML JAR-Library (this tool)
     * to build its own Data-Files.  The links here are also included above.  These links are to
     * Syntax-Hilited Source - <I>and the output it produces</I>- showing how this method &amp;
     * class may be used.  These links are also included, here, directly below:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * 
     * <LI> <B><A HREF='hilite-files/DataFiles.java.html'>
     *      Torello.BuildJAR.DataFiles.java</A></B></LI>
     * 
     * <LI> <B><A HREF='doc-files/Data-File-Builder.Output.html'>
     *      Data-File-Builder.Output.html</A></B></LI>
     * 
     * </UL>
     * 
     * @param pkgList This list of {@link BuildPackage} instances ought to be the exact same list 
     * which is passed to the {@link Config} class instance used for running a build with this 
     * package.
     * 
     * @param argv This is the {@code String[] argv} parameter received from a CLI Processor at the
     * Command-Line.
     * 
     * @param additionalCompilerArgs This should be a list
     * 
     * @param JAVAC_BIN This parameter may be null, and if it is, it shall be safely ignored.  This
     * parameter may include a relative or full path to a binary for the {@code 'javac'} program.
     * 
     * <BR /><BR />When this parameter is null, this Data-File Builder-Class will utilize whichever
     * {@code 'javac'} binary is available within the Operating-System's {@code 'PATH'}
     * Environment-Variable.
     * 
     * @throws IOException If any Operating-System I/O Errors throw.
     */
    public static void build(
            final BuildPackage[]        pkgList,
            final String[]              argv,
            final ReadOnlyList<String>  additionalCompilerArgs,
            final String                JAVAC_BIN
        )
        throws IOException
    {
        final ReadOnlyList<BuildPackage> selectedPackages = DataFilesCLI.run(pkgList, argv);

        final PkgTextBar textBarPrinter = new PkgTextBar
            (selectedPackages, "Working Package", BGREEN_BKGND, BCYAN);

        final Map<String, Integer> totals = new TreeMap<>();

        int maxLen = 0;

        for (final BuildPackage bp : selectedPackages)
        {
            textBarPrinter.print(bp);
            clearClassFiles(bp.pkgRootDirectory + "data-files" + File.separator);
            CompileDataFilesBuilders.compile(bp, additionalCompilerArgs, JAVAC_BIN);
            int numExecuted = RunDataFilesBuilders.run(bp);
            totals.put(bp.fullName, numExecuted);
            if (bp.fullName.length() > maxLen) maxLen = bp.fullName.length();
        }

        if (selectedPackages.size() > 1) printTotals(totals, maxLen+2);
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Utility / Helper Methods
    // ********************************************************************************************
    // ********************************************************************************************


    // Clear Class Files in a Directory
    private static void clearClassFiles(final String dataFilesDirName) throws IOException
    {
        final FileNode fn = FileNode
            .createRoot(dataFilesDirName)
            .loadTree(-1, FileNode.CLASS_FILES, null);

        FileTransfer.deleteFilesRecursive(fn, null, null, System.out);
    }


    // Print up the little Map that the main for-loop keeps - which contains a tally or count
    // on how many DataFileBuilderClass were found in each of the user's '../data-files/'
    // directories.

    private static void printTotals(Map<String, Integer> m, int MAX)
    {
        System.out.println(
            "\n\n" + BRED_BKGND + " Package Totals: " + RESET + "\n\n" +
            "The table below lists how many Java '.class'-Files were found within the " +
            "'../data-files/' sub-directory (and all of its sub-directories) and implemented " +
            "the 'DataFileBuilderClass' interface.  These classes were all invoked using their " +
            "respective 'DataFileBuilderClass.build(String)' methods.\n"
        );

        for (Map.Entry<String, Integer> e : m.entrySet())
        {
            final String k = e.getKey();
            final String s = StringParse.nChars(' ', MAX - k.length());
            System.out.println(k + s + e.getValue());
        }

        System.out.println();
    }
}