001package Torello.JavaDoc;
002
003import static Torello.Java.C.*;
004
005import Torello.HTML.*;
006import Torello.HTML.NodeSearch.*;
007
008import Torello.Java.FileRW;
009import Torello.Java.StringParse;
010import Torello.Java.StrCSV;
011import Torello.Java.StrIndexOf;
012
013import Torello.Java.Additional.Ret2;
014import Torello.Java.Additional.Ret3;
015
016import Torello.JDUInternal.GeneralPurpose.Messager;
017import Torello.JDUInternal.GeneralPurpose.GetHeaderTags;
018
019import Torello.JDUInternal.DataClasses.UserUpgradeFilesConfig.PkgSort;
020import Torello.JDUInternal.DataClasses.ClassUpgradeData.PathsAndTypes;
021import Torello.JDUInternal.DataClasses.ClassUpgradeData.UpgradeSettings;
022
023import Torello.JDUInternal.HTMLProcessors.Rearrange.RearrangePkgSummaryFile;
024import Torello.JDUInternal.HTMLProcessors.Rearrange.RearrangePkgFrameFile;
025
026import Torello.JDUInternal.HTMLProcessors.CleanerFixer.CleanPackageSummaryFile;
027
028import Torello.JDUInternal.HTMLProcessors.HiLiteSource.HiLiteDividers;
029
030import Torello.JDUInternal.ParseHTML.PackageSummary;
031import Torello.JDUInternal.UserConfigReaders.RetrievePkgSortConfigClass;
032
033import java.io.File;
034import java.io.IOException;
035import java.io.Serializable;
036
037import Torello.Java.ReadOnly.ReadOnlyVector;
038import Torello.Java.ReadOnly.ROTreeSetBuilder;
039import Torello.Java.ReadOnly.ReadOnlyTreeSet;
040
041import java.util.*;
042
043import java.util.function.Consumer;
044
045/**
046 * A class that parses and encapsulates the contents of a <B>{@code 'package-summary.html'}</B>
047 * File.
048 */
049public class PackageSummaryHTML implements Serializable
050{
051    // ********************************************************************************************
052    // ********************************************************************************************
053    // Static-Final Constant Fields
054    // ********************************************************************************************
055    // ********************************************************************************************
056
057
058    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
059    protected static final long serialVersionUID = 1;
060
061    /** Deprecated, but useful API Error-Message */
062    public static final String JD_FRAMES_WARNING_MESSAGE =
063        "javadoc: warning - You have specified to generate frames, by using the --frames " +
064            "option.\n" +
065        "The default is currently to not generate frames and the support for \n" +
066        "frames will be removed in a future release.\n" +
067        "To suppress this warning, remove the --frames option and avoid the use of frames.\n";
068
069    /*
070    sb.append(
071        "<UL CLASS=\"blockList\">\n" +
072        "<LI CLASS=\"blockList\">\n" +
073        "<TABLE CLASS=\"typeSummary\" BORDER=\"0\" cellpadding=\"3\" cellspacing=\"0\" " +
074        "summary=\"Summary table, listing Classes, Interfaces and Enums, etc...\">\n"
075    );
076    */
077
078    private static final Vector<HTMLNode> TABLE_START = HTMLPage.getPageTokens(
079        "<UL CLASS=blockList>\n" +
080        "<LI CLASS=blockList>\n" +
081        "<TABLE CLASS=typeSummary BORDER=0 CELLPADDING=3 CELLSPACING=0 " +
082        "summary=\"Summary table, listing Classes, Interfaces and Enums, etc...\">\n",
083        false
084    );
085
086    private static final Vector<HTMLNode> TABLE_END =
087        HTMLPage.getPageTokens("</UL>\n</LI>\n</TABLE>\n", false);
088
089    private static final char FSEP = File.separator.charAt(0);
090
091    private static final String PKG_SUMM_HTML = "Package Summary HTML";
092
093    private static final TagNode BODY_WITH_CSS_CLASS_TN = new TagNode("<BODY CLASS=C30>");
094
095
096    // ********************************************************************************************
097    // ********************************************************************************************
098    // final Class-Data Fields
099    // ********************************************************************************************
100    // ********************************************************************************************
101
102
103    /** The name of the Java Package represented by this instance. */
104    public final String packageName;
105
106    // Contains the top Navigation Bar's HTML 
107    // This, and all SubSection instances, must be private, because they are mutable
108
109    private final SubSection head;
110
111    // Contains the top Navigation Bar's HTML 
112    private final SubSection topNavBar;
113
114    // Contains the bottom Navigation Bar's HTML
115    private final SubSection bottomNavBar;
116
117    // THe Top-Description HTML/Text
118    private final SubSection description;
119
120    // The rows (which contain CIET/Types) of this 'package-summary.html' File
121    private final Vector<Vector<HTMLNode>> cietRowHTML;
122
123    private final Vector<String> cietRowSimpleNames;
124
125    private final TreeMap<String, Vector<HTMLNode>> rowTM = new TreeMap<>();
126
127    // This is needed for the "package-frame.html" file generation in later JavaDoc versions where
128    // the "--frames" switch was deprecated.  This is only used internally.
129    //
130    // Note, this could theoretically be public - although "they" wouldn't have much use for it
131    // that I can think of...  But mainly, the class "PkgSort" is not really accessible to the end
132    // user.  Therefore it shall remain package-private
133
134    final PkgSort sorter;
135
136
137    // ********************************************************************************************
138    // ********************************************************************************************
139    // Simple Accessor Methods
140    // ********************************************************************************************
141    // ********************************************************************************************
142
143
144    /**
145     * Allows a User to both retrieve and to modify the contents of the
146     * {@code 'package-summary.html'} {@code <HEAD>}-Section.
147     * 
148     * @return Vectorized-HTML of this Web-Page's {@code <HEAD>...</HEAD>} Section.
149     */
150    public Vector<HTMLNode> head() { return this.head.html; }
151
152    /**
153     * Allows a User to both retrieve and to modify the contents of the
154     * {@code 'package-summary.html'} Nav-Bar.
155     * 
156     * @return Vectorized-HTML of this Web-Page's Upper Navigation Menu-Bar.
157     */
158    public Vector<HTMLNode> topNavBar()
159    { return (this.topNavBar == null) ? null : this.topNavBar.html; }
160
161    /**
162     * Allows a User to both retrieve and to modify the contents of the
163     * {@code 'package-summary.html'} Nav-Bar.
164     * 
165     * @return Vectorized-HTML of this Web-Page's Lower Navigation Menu-Bar.
166     */
167    public Vector<HTMLNode> bottomNavBar()
168    { return (this.bottomNavBar == null) ? null : this.bottomNavBar.html; }
169
170    /**
171     * Allows a User to both retrieve and to modify the contents of the
172     * {@code 'package-summary.html'} Description Text-Area.
173     * 
174     * @return Vectorized-HTML of this Web-Page's Main Description Box.
175     */
176    public Vector<HTMLNode> description() { return this.description.html; }
177
178
179    // ********************************************************************************************
180    // ********************************************************************************************
181    // Default Package-Summary Cleaner
182    // ********************************************************************************************
183    // ********************************************************************************************
184
185
186    private static final String[] searches = { ".", "<br/>", "\n" };
187
188    public static final void defaultCleaner(Vector<HTMLNode> cietSummary)
189    {
190        // boolean VERBOSE = MessagerVerbose.isVerbose();
191
192        // System.out.println("INSIDE MY LAMBDA:\n" + Util.pageToString(cietSummary));
193
194        int i=0, nodePos=-1;
195
196        /*
197        if (VERBOSE) MessagerVerbose.println
198            ("cietSummary: " + BGREEN + Util.pageToString(cietSummary) + RESET);
199        */
200
201        while ((nodePos == -1) && (i < searches.length))
202            nodePos = TextNodeFind.first(cietSummary, TextComparitor.CN_CI, searches[i++]);
203
204        if (nodePos == -1)
205        {
206            // if (VERBOSE) MessagerVerbose.println("No String Markers Found!  Exiting...");
207            return;
208        }
209
210        String  s   = cietSummary.elementAt(nodePos).str;
211        int     pos = StrIndexOf.first_CI(s, searches[--i]);
212
213        /*
214        if (VERBOSE) MessagerVerbose.println("s: " + s);
215        */
216
217        s = s.substring(0, pos);
218
219        /*
220        if (VERBOSE) MessagerVerbose.println("s.substring: " + s);
221        */
222
223        if (s.length() != 0)
224            cietSummary.setElementAt(new TextNode(s), nodePos++);
225
226        if (nodePos < cietSummary.size())
227            Util.Remove.range(cietSummary, nodePos, cietSummary.size());
228
229        // Util.removeAllTagNodes(cietSummary);
230        // CHANGED March 2nd 2022
231
232        TagNodeRemove.allExcept(cietSummary, TC.Both, "a", "b", "i", "code", "span");
233
234        /*
235        if (VERBOSE) MessagerVerbose.println(
236            BCYAN + Util.pageToString(cietSummary) + RESET +
237            "\n************************************************************\n"
238        );
239        */
240    }
241
242
243    // ********************************************************************************************
244    // ********************************************************************************************
245    // This class Main-Builder (Constructor)
246    // ********************************************************************************************
247    // ********************************************************************************************
248
249
250    public PackageSummaryHTML(
251            final String                jdPkgSummFName,
252            final PathsAndTypes.Builder pathsTypesBuilder,
253            final UpgradeSettings       settings
254        )
255    {
256        Messager.setCurrentFileName(jdPkgSummFName, "'package-summary.html' File");
257
258        final String dotDotsFileSystem = StringParse.dotDots
259            (jdPkgSummFName, pathsTypesBuilder.rootJavaDocDirectory, File.separatorChar);
260
261        final String dotDotsUrls = (File.separatorChar == '/')
262            ? dotDotsFileSystem
263            : dotDotsFileSystem.replace(File.separatorChar, '/');
264
265        final Consumer<Vector<HTMLNode>> packageSummaryCleaner = settings.packageSummaryCleaner;
266
267
268        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
269        // Calculate the Package-Name.  This is the very first time this is done.
270        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
271
272        final String packageSubDir = jdPkgSummFName.substring(
273            pathsTypesBuilder.rootJavaDocDirectory.length(),
274
275            // "/package-summary.html" ==> String-Length = 21
276            jdPkgSummFName.length() - 21
277        );
278
279        // As of February, 2024, this is now a public final String field
280        packageName = packageSubDir.replace(FSEP, '.');
281
282        // Read the file from disk and parse into Vectorized-HTML
283        Vector<HTMLNode> fileVec =
284            loadHTMLFile(jdPkgSummFName, "package-summary.html");
285
286
287        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
288        // Check for a PackageSummarySort.class File - check all Class-Path Source-Code Dirs
289        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
290
291        final ArrayList<String> sorters = new ArrayList<>(4);
292
293        for (String dir : pathsTypesBuilder.rootSourceFileDirectories)
294        {
295            String fileName = dir + packageSubDir + FSEP + "upgrade-files" + FSEP +
296                "config-classes" + FSEP + "PackageSummarySort.class";
297
298            File f = new File(fileName);
299
300            if (f.exists() && f.isFile()) sorters.add(fileName);
301        }
302
303        if (sorters.size() > 1) Messager.userErrorHalt(
304            "Multiple Package Sorters were found:\n" +
305            StrCSV.toCSV(sorters, fName -> "    " + fName + '\n', true, null)
306        );
307
308        // This is an instance of "PkgSort"  As of February 2024, it must be retained as an 
309        // instance-field of this class, in case the "package-frame.html" file must be built from
310        // scratch.  (Thereby allowing for later javadoc versions, where `--frames` was deprecated
311        // to continue to have a 'packge-frame.html' file anyway)
312
313        sorter = (sorters.size() == 0)
314            ? null
315            : RetrievePkgSortConfigClass.readConfigurationClassFromDisk
316                (sorters.get(0), packageName);
317
318
319        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
320        // Sort **OR** just Clean-Up the CIET/Type List on this web-page
321        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
322
323        if (sorter != null)
324        {
325            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
326            // Read the File's Contents & Sort if needed.
327            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
328
329            // Used to build the Master CIET/Type List for registering with 'pathsTypes'
330            ROTreeSetBuilder<String> cietSimpleNamesList = new ROTreeSetBuilder<>();
331
332            // Builds a TreeMap of all of the table rows on the "Package Summary" JavaDoc HTML Page
333            HNLIInclusive iter = PackageSummary.iteratorTypeRows(fileVec);
334
335            // Save the rows by CIET-Name in a TreeMap
336            // Map-Key:     CIET Simple-Name
337            // Map-Value:   Table-Row of HTML <TR> ... </TR>
338
339            final TreeMap<String, Vector<HTMLNode>> entries = new TreeMap<>();
340
341            // Fill the TreeMap with all of the table-rows on the page.  These are going to be
342            // completely rearranged in the next step.
343
344            while (iter.hasNext())
345            {
346                Vector<HTMLNode>    cietHTML        = iter.next();
347                int                 pos             = TagNodeFind.first(cietHTML, TC.OpeningTags, "a");
348                String              cietSimpleName  = cietHTML.elementAt(pos + 1).str;
349
350                entries.put(cietSimpleName, cietHTML);      // Saved for Sorting
351                cietSimpleNamesList.add(cietSimpleName);    // Saved to PathsAndTypes
352            }
353
354            final Ret2<
355                Vector<String>,
356                Vector<Vector<HTMLNode>>
357            > r2 = RearrangePkgSummaryFile.run(sorter.sections, sorter.types, entries);
358
359            // If there were errors, then the above function might return null.  Halt the
360            // constructor here, BUT do not throw so that all of the PackageSummaryHTML's can
361            // execute, FIRST, before quitting.
362
363            if (r2 == null)
364            {
365                // Prevent `javac` complaints: (final field may not have been initialized)
366                this.cietRowHTML        = null;
367                this.cietRowSimpleNames = null;
368
369                // These are all SubSection instances
370                this.head = this.topNavBar = this.bottomNavBar = this.description = null;
371
372                return;
373            };
374
375            this.cietRowSimpleNames = r2.a;
376            this.cietRowHTML        = r2.b;
377
378            // Update the Global Package-Name ==> CIET/Type List TreeMap (Inside PathsAndTypes)
379            pathsTypesBuilder.packageCIETLists.put(packageName, cietSimpleNamesList.build());
380        }
381
382        else
383        {
384            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
385            // Read the File's Contents & Clean-It
386            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
387
388            Ret3
389            <
390                Vector<String>,             // cietRowSimpleNames
391                Vector<Vector<HTMLNode>>,   // cietRowHTML
392                ReadOnlyTreeSet<String>     // cietSimpleNamesList
393            >
394            r3 = CleanPackageSummaryFile.run(fileVec);
395
396            this.cietRowSimpleNames = r3.a;
397            this.cietRowHTML        = r3.b;
398
399            // Update the Global Package-Name ==> CIET/Type List TreeMap (Inside PathsAndTypes)
400            pathsTypesBuilder.packageCIETLists.put(packageName, r3.c);
401        }
402
403
404        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
405        // Build the Updated 'package-summary.html' Page
406        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
407
408        // This DotPair contains the entire Summary-Table in a package-summary.html file
409        DotPair dp = InnerTagFindInclusive.first
410            (fileVec, "ul", "class", TextComparitor.C, "blockList");
411
412        // Build the new Package-Summary CIET/Type Table
413        final Vector<HTMLNode> newTable = new Vector<>();
414
415        newTable.addAll(TABLE_START);
416
417        for (Vector<HTMLNode> cietHTML : this.cietRowHTML) newTable.addAll(cietHTML);
418
419        newTable.addAll(TABLE_END);
420
421        // Insert the new Table into the same location where the old table had been placed
422        ReplaceNodes.r(fileVec, dp, newTable);
423
424
425        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
426        // Check if there is a User-Provided (or Default) "Package Summary Cleaner"
427        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
428
429        // MESSAGER: Messager.isVerbose, println only
430        if (packageSummaryCleaner != null)
431            CleanPackageSummaryFile.run(fileVec, packageSummaryCleaner);
432
433        // MESSAGER:
434        //  1) INVOKES:     assertFailGeneralPurpose, assertFailHTML
435        //  2) INVOKED-BY:  ExtraFilesProcessor (once) MainFilesProcessor (once), method above
436        //  3) RETURNS:     Number of HiLited <DIV>'s (maybe zero, if zero)
437        //  4) THROWS:      asserFail ==> JavaDocHTMLParseException & UpgradeException
438
439        HiLiteDividers.hiLite(fileVec, settings.hiLiter);
440
441
442        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
443        // Retrieve the <HEAD>...</HEAD> Header
444        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
445
446        this.head = TagNodePeekInclusive.first(fileVec, "head");
447
448        if (this.head == null) Messager.assertFailHTML(
449            "This 'package-summary.html' page does not appear to have a <HEAD>...</HEAD> Element",
450            PKG_SUMM_HTML
451        );
452
453
454        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
455        // The Top Navigation-Bar - There may be pages which do not have a NavBar
456        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
457        //
458        // NOTE: I just noticed that the Navigation-Bar is a series of <DIV>'s, and there is no
459        //       surrounding HTML divider.  We have to find the first open-<DIV>, and the last
460        //       closing </DIV>
461
462        int sPos = CommentNodeFind.first
463            (fileVec, head.location.end, -1, s -> s.contains("=== START OF TOP NAVBAR ==="));
464
465        int ePos;
466
467        if (sPos == -1)
468        {
469            this.topNavBar = null;
470            ePos = head.location.end;
471        }
472
473        else
474        {
475            ePos = CommentNodeFind.first
476                (fileVec, sPos, -1, s -> s.contains("=== END OF TOP NAVBAR ==="));
477
478            sPos = TagNodeFind.first(fileVec, sPos, ePos, TC.OpeningTags, "div");
479            ePos = TagNodeFind.last(fileVec, sPos, ePos, TC.ClosingTags, "div");
480
481            dp = new DotPair(sPos, ePos);
482
483            this.topNavBar = new SubSection(dp, Util.cloneRange(fileVec, dp));
484        }
485
486
487        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
488        // Package-Description
489        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
490
491        this.description = TagNodePeekInclusive.first(fileVec, ePos, -1, "section");
492
493        if (this.description == null) Messager.assertFailHTML
494            ("This Package returned a null Description", PKG_SUMM_HTML);
495
496
497        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
498        // The Bottom Navigation-Bar, There may be pages which do not have a NavBar
499        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
500        //
501        // Searching through "CommentNode" instances is much faster since the
502        // if (HTMLNode.isCommentNode()) is the fastest of the search-specifies...  There aren't
503        // many comment's in a javadc page (much fewer than the number of TagNode's & TextNode's)
504        //
505        // ALSO: as explained in the "Top Navigation-Bar" getter-section (way above this part),
506        //       The Bottom and Top Bar's are a series of "sibling" <DIV> Tags, and you have to
507        //       get the first opening-<DIV> and the last closing-</DIV>
508
509        sPos = CommentNodeFind.first(fileVec, s -> s.contains("== START OF BOTTOM NAVBAR =="));
510
511        if (sPos == -1) this.bottomNavBar = null;
512
513        else
514        {
515            ePos = CommentNodeFind.first
516                (fileVec, sPos, -1, s -> s.contains("=== END OF BOTTOM NAVBAR ==="));
517
518            if (ePos == -1) Messager.assertFailHTML("BOTTOM NAVBAR End-Marker not found", null);
519
520            sPos = TagNodeFind.first(fileVec, sPos, ePos, TC.OpeningTags, "div");
521            ePos = TagNodeFind.last(fileVec, sPos, ePos, TC.ClosingTags, "div");
522    
523            dp = new DotPair(sPos, ePos);
524
525            this.bottomNavBar = new SubSection(dp, Util.cloneRange(fileVec, dp));
526        }
527
528
529        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
530        // Meta-Tags in Header, Stats Button in Navigation Bar
531        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
532
533        final List<HTMLNode> tags = GetHeaderTags.packageSummaryHTMLTags(
534                ((settings.cssFiles == null) ? null : settings.cssFiles.customizedCSS),
535                dotDotsUrls,
536                settings.faviconImageFileName,
537                settings.headerTags
538            )
539            .wrapToImmutableList();
540
541        this.head.html.addAll(1, tags);
542
543        Stats.addStatsButton(this.topNavBar(), this.bottomNavBar(), dotDotsUrls, packageName);
544
545
546        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
547        // Re-Build the Page-Vector
548        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
549
550        Replaceable[] replaceables =
551            { this.head, this.topNavBar, this.description, this.bottomNavBar };
552
553        fileVec = ReplaceNodes.r(fileVec, Arrays.asList(replaceables), false).a;
554
555
556        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
557        // Write the new 'package-summary.html' to Disk
558        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
559
560        try
561            { FileRW.writeFile(Util.pageToString(fileVec), jdPkgSummFName); }
562
563        catch (IOException ioe)
564        {
565            Messager.assertFailGeneralPurpose
566                (ioe, "Failed Writing 'package-summary.html' File", null);
567        }
568
569
570        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
571        // Handle 'package-frame.html' - IF IT EXISTS
572        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
573        //
574        // Requirements:
575        //      1) User has provided a Package-Sorter
576        //      2) JavaDoc has created a package-frame.html file
577
578        // "package-summary.html" ==> "summary.html" ==> length() is 12
579        final String jdPkgFrameFName =
580            jdPkgSummFName.substring(0, jdPkgSummFName.length() - 12) + "frame.html";
581
582        final File f = new File(jdPkgFrameFName);
583
584        // Now check that the package-frame.html file exists, and is an HTML-File
585        if (f.exists() && f.isFile())
586        {
587            Messager.setCurrentFileName(jdPkgSummFName, "'package-frame.html' File");
588    
589            // Read the file from disk and parse into Vectorized-HTML
590            fileVec =
591                loadHTMLFile(jdPkgFrameFName, "package-summary.html");
592
593
594            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
595            // Rearrange 'package-frame.html'
596            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
597
598            if (sorter != null)
599                RearrangePkgFrameFile.run(fileVec, sorter.sections, sorter.types);
600
601
602            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
603            // Original "Package-Frame Cleaner" - Moved Here from EFP, November 2023
604            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
605
606            fileVec.setElementAt(
607                BODY_WITH_CSS_CLASS_TN,     /* <BODY CLASS=C30> */
608                TagNodeFind.first(fileVec, TC.OpeningTags, "body")
609            );
610
611            /*
612            // February 2024, EVEN-BETTER
613            // Just do <BODY CLASS=C30> inside of a 'package-frame.html' file INSTEAD OF ALL OF
614            // THESE STUPID "extra CSS Classses"
615            // SEE ABOVE 3 LOC
616
617            for (TagNodeIndex tni : TagNodePeek.all(fileVec, TC.OpeningTags, "h1", "h2", "ul"))
618
619                if (tni.n.tok.equals("h1"))            
620                    fileVec.setElementAt(
621                        tni.n.appendCSSClass(CSSTags.CSS_CLASS_FOR_PKG_FRAME_H1, null),
622                        tni.index
623                    );
624
625                else if (tni.n.tok.equals("h2"))
626                    fileVec.setElementAt(
627                        tni.n.appendCSSClass(CSSTags.CSS_CLASS_FOR_PKG_FRAME_H2, null),
628                        tni.index
629                    );
630
631                else // if (tni.n.tok.equals("ul"))
632                    fileVec.setElementAt(
633                        tni.n.appendCSSClass(CSSTags.CSS_CLASS_FOR_PKG_FRAME_UL, null),
634                        tni.index
635                    );
636            */
637
638
639            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
640            // Meta-Tags in Header
641            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
642
643            final int pkgFrameHeaderPos = TagNodeFind.first(fileVec, TC.OpeningTags, "HEAD");
644
645            fileVec.addAll(pkgFrameHeaderPos + 1, tags);
646
647
648            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
649            // Write 'package-frame.html' back to disk
650            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
651
652            try
653                { FileRW.writeFile(Util.pageToString(fileVec), jdPkgFrameFName); }
654
655            catch (IOException ioe)
656            {
657                Messager.assertFailGeneralPurpose
658                    (ioe, "Failed Writing 'package-summary.html' File", null);
659            }
660        }
661
662    }
663
664
665    // ********************************************************************************************
666    // ********************************************************************************************
667    // A Little Helper That Could
668    // ********************************************************************************************
669    // ********************************************************************************************
670
671
672    private static Vector<HTMLNode> loadHTMLFile(final String fileName, final String fileKind)
673    {
674        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
675        // Load The Package-Summary HTML File from disk.
676        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
677
678        // Temp Variable, the file as a String
679        final String fileAsStr;
680
681        try
682            { fileAsStr = FileRW.loadFileToString(fileName); }
683
684        catch (Exception e)
685        {
686            throw (Error) /* Shut-Up Compiler */ Messager.assertFailGeneralPurpose(
687                e,
688                "I/O Exception throwm attempting to load " + fileKind + " file from disk",
689                null
690            );
691        }
692
693
694        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
695        // Parse The Summary HTML File from the raw-file text-string
696        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
697
698        // This portion of the code attempts to load the Package-Frame list of classes, 
699        // interfaces enums, errors and exceptions into a Vectorized-HTML page.
700
701        final Vector<HTMLNode> fileVec;
702
703        try
704            { fileVec = HTMLPage.getPageTokens(fileAsStr, false); }
705
706        // It seems ridiculous to check for this exception, but oh well, this always does have
707        // the upside that if class HTMLPage does break (for whatever reason), what has
708        // happened would be much easier to identify
709
710        catch (Exception e)
711        {
712            throw (Error) /* Shut-Up Compiler */ Messager.assertFailHTML(
713                e,
714                "Error Parsing HTML in file " + fileKind + " using class HTMLPage.parsePgeTokens",
715                null
716            );
717        }
718
719        return fileVec;
720    }
721}