001package Torello.HTML.Tools.JavaDoc;
002
003import java.io.Serializable;
004
005import java.util.*;
006import java.util.stream.*;
007
008import Torello.HTML.*;
009import Torello.HTML.NodeSearch.*;
010import Torello.Java.*;
011
012import static Torello.Java.Shell.C.*;
013
014/**
015 * As the Upgrade Processor are executed, this class maintains a few statistics about the build,
016 * and produces the {@code Stats} HTML, which is subsequently linked to a {@code 'Stats'} button
017 * on output Java Doc Web-Pages.
018 * 
019 * <BR /><BR /><EMBED CLASS="external-html" DATA-FILE-ID="UPSTATS">
020 */
021public class Stats implements java.io.Serializable
022{
023    /** <EMBED CLASS="external-html" DATA-FILE-ID=SVUID> */
024    protected static final long serialVersionUID = 1;
025
026    // Package-Level instances of 'Stats' will have their package-names saved here.
027    // For the "Complete-Project" Stats instance, this will be null.
028    private final String packageName;
029
030    // Each Package has it's own / recursive instance of 'Stats'
031    // For the Package-Level instances of 'Stats' - this field will be null.
032    private final Map<String, Stats> packageStatsMap;
033
034    /**
035     * Global Stats are maintained, but so are package-local statistics.  This reetrieves the
036     * package-local statistics instance.
037     * @param packageName The name of one of the upgraded Java Packages, as a {@code String}.
038     * @return The package-level instance of {@code 'Stats'} for that package.
039     */
040    public Stats getPackageStats(String packageName)
041    { return packageStatsMap.get(packageName); }
042
043    // A Pointer to the "Project-Global Embed-Tags Map"
044    private final Map<String, String> globalTagsMap;
045
046    // A Count-Total for the "Project-Global Embed-Tags Map"
047    private final Map<String, Integer> globalTagsCount;
048
049    /**
050     * Retrieving a count of all Project-Global Tags is done with this getter.  <I>It is important
051     * to remember that an instance of {@code 'Stats'} may be a <B>Project-Global</B> instance, or a
052     * <B>Package-Local</B> instance</I>.  If {@code 'this'} instance of {@code Stats} is the 
053     * 'Project-Global' instance, the integer count-values inside the returned-{@code Map} will be
054     * aggregate totals (for the whole project) of the number of times your External-HTML
055     * {@code <EMBED>} tags were used.
056     * 
057     * <BR /><BR />If this method is invoked on one of the Package-Local {@code 'Stats'} instances,
058     * the returned-{@code Map} will hold integer count-values for the Project-Global
059     * {@code <EMBED>} tags were used <I>inside the particular package for which {@code 'this'}
060     * statistics-instance was built.</I>
061     * 
062     * <BR /><BR /><B STYLE='color:red'>NOTE:</B> The complete dump of the statistics-tables for
063     * the Java HTML Jar Library may be viewed by clicking on the {@code 'Stats'} link in the top
064     * right corner of this page.  The data-tables there show the exact data that's inside the
065     * {@code Map's}-tables of this class.
066     * 
067     * @return If {@code 'this'} instance of {@code 'Stats'} is the 'Project-Global' instance, the
068     * returned-{@code Map} will be the 'Project-Totals' use-count for all Globally-Defined
069     * {@code <EMBED class='external-html ..>'} Tags.
070     * 
071     * <BR /><BR />If {@code 'this'} instance of {@code 'Stats'} is a 'Package-Local' instance,
072     * the returned-{@code Map} will have <B>Package-Local use-counts</B> for all of the
073     * <B>Globallly-Defined Tags.</B>
074     */
075    @SuppressWarnings("unchecked")
076    public Map<String, Integer> getGlobalTagsCount()
077    { return (HashMap<String, Integer>) ((HashMap<String, Integer>) globalTagsCount).clone(); }
078
079    // A reference pointer to the "Package-Local Embed-Tag Map", (ID's ==> FileNames)
080    // NOTE: For the top-level main 'Stats' instance, this will remain null
081
082    private final Map<String, String> packageTagsMap;
083
084    // Keeps a count of the use of all "Package-Local Embed-Tags"
085    // NOTE: For the top-level main 'Stats' instance, this will remain null
086
087    private final Map<String, Integer> packageTagsCount;
088
089    /**
090     * This retrieves an integer count-{@code Map} of all Package-Local Embedded HTML
091     * (External-HTML) Tags.  If {@code 'this'} instance of {@code 'Stats'} is the Top-Level,
092     * Project-Global instance of {@code 'Stats'}, this method returns null.
093     * 
094     * @return A {@code Map} containing counts of the number of times a Package-Local
095     * {@code <EMBED CLASS='external-html'>} Tag has been used on web-pages that are inside
096     * that particular package.
097     *
098     * <BR /><BR />This method returns null if {@code 'this'} instance of {@code 'Stats'} is
099     * the Global-Instance, rather than one of the Package-Local Instances.
100     */
101    @SuppressWarnings("unchecked")
102    public Map<String, Integer> getPackageTagsCount()
103    {
104        return (packageTagsCount == null)
105            ? null
106            : (HashMap<String, Integer>) ((HashMap<String, Integer>) packageTagsCount).clone();
107    }
108
109    // This builds a "Global Stats" that doesn't have any Global Embed-Tags.  This is the constructor
110    // used by configuration-class "Upgrade" in the "fields initializers" section.
111    //
112    // SPECIFICALLY: The following line is the "first initialization used".
113    //              protected Stats stats = new Stats();
114    //
115    // If the User registers a global Embed-Tags Map, then this instance is SIMPLY-DISCARDED 
116    // (Garbage Collected), and a new instance assigned to that Upgrade Field.
117    //
118    // AGAIN: Usually this instance is built, **BUT** then replaced if the user configures the
119    //        upgrade class with a Global Embed Tags map.  In the Java HTML JAR an instance is
120    //        built using this constructor, but then destoyed immediately after registering.
121    //        This is not a big enough waste - when compared to the alternative (which is writing
122    //        another "register map" method).
123    //
124    // FOR USERS WHO DO NOT REGISTER A GLOBAL EMBED TAGS MAP, THE INSTANCE CREATED BY THIS
125    // CONSTRFUCTOR - OBVIOUSLY - WON'T BE GARBAGE COLLECTED.
126
127    Stats()
128    {
129        this.packageName        = null;
130        this.packageStatsMap    = new HashMap<>();
131        this.packageTagsMap     = null;
132        this.packageTagsCount   = null;
133        this.globalTagsMap      = null;
134        this.globalTagsCount    = null;
135    }
136
137    // Constructor for global-stats instance 
138    // NO MESSGER USE
139
140    Stats(Map<String, String> globalTagsMap)
141    {
142        // This is a 'JavaDocError' rather than a message to the messager because this should
143        // *NEVER* occur.  At the time of the writing of this exception-check, this constructor is
144        // invoked from the 'Upgrade' Confguration class.  A null-check is done there on th euser
145        // input.  If that changes or moves, it should be thought of as "My Fault" not
146        // "Their Fault" - so this has to be a 'THROW' rather than a 'MESSAGER' error.
147        //
148        // Keep these here because this class seems Ultra-Simple at first glance, but because it
149        // is ALL ABOUT DATA, it is sort of more DIFFICULT than one might expect.
150        //
151        // The Exception/Errors in this class ARE ALL FOR MISTAKES that should NEVER happen, NO
152        // MATTER WHAT the user has entered or passed to the Upgrade-Configuration class.
153
154        if (globalTagsMap == null) throw new JavaDocError(
155            "A null 'globalTagsMap' was passed to the Stats Constructor.  If there are no " +
156            "Global Embed Tags being used with this Project, the Upgrade-Configuration class " +
157            "is supposed to be using the Stats-class zero-argument constructor"
158        );
159
160        this.packageName        = null;
161        this.packageStatsMap    = new HashMap<>();
162
163        // The "Global Stats" instance doesn't have PackageTags
164        // AGAIN: This constructor is the Constructor for the "Global Stats" instance.
165
166        this.packageTagsMap     = null;
167        this.packageTagsCount   = null;
168
169        this.globalTagsMap      = globalTagsMap;
170        this.globalTagsCount    = new HashMap<>();
171
172        // This must be initialized here.  Even if a Tag is not used, knowing that it's count
173        // is ZERO is helpful to the user.  If we leave it null here, yes, that could be
174        // interpreted as a ZERO, but it looks nicer here, and at the end to put a zero, rather
175        // than leaving it null and reverse-checking the global-map.
176
177        Integer ZERO = Integer.valueOf(0);
178
179        // Initialize the PROJECT-GLOBAL tag-count map.
180        for (String embedTag : globalTagsMap.keySet()) this.globalTagsCount.put(embedTag, ZERO);
181    }
182
183    // Constructor for package-stats instances
184    private Stats(String packageName, Map<String, String> packageTagsMap)
185    {
186        this.packageName        = packageName;
187        this.packageStatsMap    = null;         // This instance **IS** a "Package Stats"
188
189        this.globalTagsMap      = null;         // This is not needed
190        this.globalTagsCount    = new HashMap<>();
191
192        this.packageTagsMap     = packageTagsMap;
193        this.packageTagsCount   = (packageTagsMap == null) ? null : new HashMap<>();
194
195        Integer ZERO = Integer.valueOf(0);
196
197        if (packageTagsCount != null)
198            for (String embedTag : this.packageTagsMap.keySet())
199                this.packageTagsCount.put(embedTag, ZERO);
200    }
201
202    // This is called by "MainFilesProcessor" right before processing the Java Doc Web-Pages
203    // for a particular Java Package.  At this point in that code, the 'packageTagsMap' has just
204    // been read in from the 'upgrade-files/external-html/external-html-ids.properties' file.
205    // If the user didn't write any External-HTML Files, then the 'packageTagsMap' instance will
206    // be null.
207
208    void registerPackage
209        (String packageName, Map<String, String> packageTagsMap, Stats topLevelStatsInstance)
210    {
211        // AGAIN: This should never be null, no matter what input the user has provided.  If
212        //        this is null, it means (mostly) that something else was changed (probably in
213        //        class 'Upgrade' or 'MainFilesProcessor').  Throw this to signify that it is
214        //        MY FAULT - NOT THEIR FAULT.
215
216        if (topLevelStatsInstance == null) throw new JavaDocError(
217            "The instance of 'Stats' passed to constructor-parameter 'topLevelStatsInstance' " +
218            "null.  Niether the top-level 'Stats' instance, nor the Package-Local instances " +
219            "should ever be null.\nNOTE: Currently attempting to build Package-Local 'Stats' " +
220            "instance for package [" + packageName + "]."
221        );
222
223        topLevelStatsInstance.packageStatsMap.put
224            (packageName, new Stats(packageName, packageTagsMap));
225    }
226
227    /** The name of the Statistics HTML file saved to the root JavaDoc Directory. */
228    protected static final String STATS_HTML_FILENAME = "Stats.html";
229
230
231    // ********************************************************************************************
232    // ********************************************************************************************
233    // Stats Fields: BASIC
234    // ********************************************************************************************
235    // ********************************************************************************************
236
237
238    /** @return A count of the total number of lines of {@code '.java'} files. */
239    public int numLines() { return numLines; }
240    private int numLines;
241
242    /** @return A count of the total number of bytes of {@code '.java'} files. */
243    public int numBytes() { return numBytes; }
244    private int numBytes;
245
246    /** @return A count of the total number of HiLited HTML {@code <DIV>} Elements. */
247    public int numHiLitedDivs() { return numHiLitedDivs; }
248    private int numHiLitedDivs = 0;
249
250
251    // ********************************************************************************************
252    // ********************************************************************************************
253    // Stats: Entity (METHOD, FIELD, CONSTRUCTOR, ANNOTATION_ELEM, ENUM_CONSTANT)
254    // ********************************************************************************************
255    // ********************************************************************************************
256
257
258    /** @return A count of the total number of methods found during the upgrade. */
259    public int numMethods() { return numMethods; }
260    private int numMethods = 0;
261
262    /** @return A count of the total number of constructors found during the upgrade. */
263    public int numConstructors() { return numConstructors; }
264    private int numConstructors = 0;
265
266    /** @return A count of the total number of fields found during the upgrade. */
267    public int numFields() { return numFields; }
268    private int numFields = 0;
269
270    /** @return A count of the total number of annotation-elements found during the upgrade. */
271    public int numAnnotationElems() { return numAnnotationElems; }
272    private int numAnnotationElems = 0;
273
274    /** @return A count of the total number of enum-constants found during the upgrade. */
275    public int numEnumConstants() { return numEnumConstants; }
276    private int numEnumConstants = 0;
277
278
279    // ********************************************************************************************
280    // ********************************************************************************************
281    // Stats: HILITED-Entity (METHOD, FIELD, CONSTRUCTOR, ANNOTATION_ELEM, ENUM_CONSTANT)
282    // ********************************************************************************************
283    // ********************************************************************************************
284
285
286    /** @return A count of the total number of method bodies hilited by the upgrader. */
287    public int numHiLitedMethods() { return numHiLitedMethods; }
288    private int numHiLitedMethods = 0;
289
290    /** @return A count of the total number of constructor bodies hilited by the upgrader. */
291    public int numHiLitedConstructors() { return numHiLitedConstructors; }
292    private int numHiLitedConstructors = 0;
293
294    /** @return A count of the total number of field declarations hilited by the upgrader. */
295    public int numHiLitedFields() { return numHiLitedFields; }
296    private int numHiLitedFields = 0;
297
298    /**
299     * @return A count of the total number of annotation-element declarations hilited by the
300     * upgrader.
301     */
302    public int numHiLitedAnnotationElems() { return numHiLitedAnnotationElems; }
303    private int numHiLitedAnnotationElems = 0;
304
305    /**
306     * @return A count of the total number of enumeration-constant declarations hilited by the
307     * upgrader.
308     */
309    public int numHiLitedEnumConstants() { return numHiLitedEnumConstants; }
310    private int numHiLitedEnumConstants = 0;
311
312
313    // ********************************************************************************************
314    // ********************************************************************************************
315    // Stats: DOCUMENTED-Entity (METHOD, FIELD, CONSTRUCTOR, ANNOTATION_ELEM, ENUM_CONSTANT)
316    // ********************************************************************************************
317    // ********************************************************************************************
318
319
320    /** @return A count of the total number of methods that were documented by Java Doc. */
321    public int numDocumentedMethods() { return numDocumentedMethods; }
322    private int numDocumentedMethods = 0;
323
324    /** @return A count of the total number of constructors that were documented by Java Doc. */
325    public int numDocumentedConstructors() { return numDocumentedConstructors; }
326    private int numDocumentedConstructors = 0;
327
328    /** @return A count of the total number of fields that were documented by Java Doc. */
329    public int numDocumentedFields() { return numDocumentedFields; }
330    private int numDocumentedFields = 0;
331
332    /**
333     * @return A count of the total number of annotation-elements that were documented by
334     * Java Doc.
335     */
336    public int numDocumentedAnnotationElems() { return numDocumentedAnnotationElems; }
337    private int numDocumentedAnnotationElems = 0;
338
339    /**
340     * @return A count of the total number of annotation-elements that were documented by
341     * Java Doc.
342     */
343    public int numDocumentedEnumConstants() { return numDocumentedEnumConstants; }
344    private int numDocumentedEnumConstants = 0;
345
346
347    // ********************************************************************************************
348    // ********************************************************************************************
349    // Stats: STATIC-Entity (METHOD, FIELD)
350    // ********************************************************************************************
351    // ********************************************************************************************
352
353
354    /** @return A count of the total number of {@code static} methods found during the upgrade. */
355    public int numStaticMethods() { return numStaticMethods; }
356    private int numStaticMethods = 0;
357
358    /** @return A count of the total number of {@code static} fields found during the upgrade. */
359    public int numStaticFields() { return numStaticFields; }
360    private int numStaticFields = 0;
361
362
363    // ********************************************************************************************
364    // ********************************************************************************************
365    // Stats: FINAL-Entity (METHOD, FIELD, CONSTRUCTOR)
366    // ********************************************************************************************
367    // ********************************************************************************************
368
369
370    /** @return A count of the total number of {@code final} methods found by the upgrade. */
371    public int numFinalMethods() { return numFinalMethods; }
372    private int numFinalMethods = 0;
373
374    /** @return A count of the total number of {@code final} constructors found by the upgrader. */
375    public int numFinalConstructors() { return numFinalConstructors; }
376    private int numFinalConstructors = 0;
377
378    /** @return A count of the total number of {@code final} fields found by the upgrader. */
379    public int numFinalFields() { return numFinalFields; }
380    private int numFinalFields = 0;
381
382
383    // ********************************************************************************************
384    // ********************************************************************************************
385    // Stats: PUBLIC-Entity (METHOD, FIELD, CONSTRUCTOR)
386    // ********************************************************************************************
387    // ********************************************************************************************
388
389
390    /** @return A count of the total number of {@code public} methods found by the upgrader. */
391    public int numPublicMethods() { return numPublicMethods; }
392    private int numPublicMethods = 0;
393
394    /** @return A count of the total number of {@code public} constructors found by the upgrader.*/
395    public int numPublicConstructors() { return numPublicConstructors; }
396    private int numPublicConstructors = 0;
397
398    /** @return A count of the total number of {@code public} fields found by the upgrader. */
399    public int numPublicFields() { return numPublicFields; }
400    private int numPublicFields = 0;
401
402
403    // ********************************************************************************************
404    // ********************************************************************************************
405    // Stats: PROTECTED-Entity (METHOD, FIELD, CONSTRUCTOR)
406    // ********************************************************************************************
407    // ********************************************************************************************
408
409
410    /** @return The total number of {@code protected} methods found during the upgrade. */
411    public int numProtectedMethods() { return numProtectedMethods; }
412    private int numProtectedMethods = 0;
413
414    /** @return The total number of {@code protected} constructors found during the upgrade. */
415    public int numProtectedConstructors() { return numProtectedConstructors; }
416    private int numProtectedConstructors = 0;
417
418    /** @return The total number of {@code protected} fields found during the upgrade. */
419    public int numProtectedFields() { return numProtectedFields; }
420    private int numProtectedFields = 0;
421
422
423    // ********************************************************************************************
424    // ********************************************************************************************
425    // Stats: PRIVATE-Entity (METHOD, FIELD, CONSTRUCTOR)
426    // ********************************************************************************************
427    // ********************************************************************************************
428
429
430    /** @return The total number of {@code private} methods found during the upgrade. */
431    public int numPrivateMethods() { return numPrivateMethods; }
432    private int numPrivateMethods = 0;
433
434    /** @return The total number of {@code private} constructors found during the upgrade. */
435    public int numPrivateConstructors() { return numPrivateConstructors; }
436    private int numPrivateConstructors = 0;
437
438    /** @return The total number of {@code private} fields found during the upgrade. */
439    public int numPrivateFields() { return numPrivateFields; }
440    private int numPrivateFields = 0;
441
442
443    // ********************************************************************************************
444    // ********************************************************************************************
445    // Stats: OTHER-Entity (FIELD only)
446    // ********************************************************************************************
447    // ********************************************************************************************
448
449
450    /** @return A count of the total number of {@code transient} fields found during the upgrade.*/
451    public int numTransientFields() { return numTransientFields; }
452    private int numTransientFields = 0;
453
454    /** @return A count of the total number of {@code volatile} fields found during the upgrade. */
455    public int numVolatileFields() { return numVolatileFields; }
456    private int numVolatileFields = 0;
457
458
459
460    // ********************************************************************************************
461    // ********************************************************************************************
462    // Stats Per Package, **AND** Embed-Tags Stats
463    // ********************************************************************************************
464    // ********************************************************************************************
465
466
467    // ***Optimization Fields***
468    // The same package will be referenced, over and over, until the package has completed
469    // These tags are used hundreds of times in some of the packages.
470    private String LAST_USED_packageName = null;
471    private Stats LAST_USED_packageStats = null;
472
473
474    // Increments the total-count by 1 for a particular embed-tag
475    //
476    // NOTE: The whole 'LAST_USED_' PHENOMENON is an optimization, so that these tables are not
477    //       looked up in the Hashtable every single time they are used.
478    //
479    // MESSAGER:
480    //  1) SETS:        processorName
481    //  2) EXPECTS:     file-name
482    //  3) INVOKES:     assertFailGeneralPurpose (100% my fault, not there fault)
483    //  4) INVOKED-BY:  **ONLY ONCE**, from 'EmbedTag', (inside a loop)
484    //  5) RETURN:      NOTHING
485    //  6) THROWS:      UpgradeException (from assert statement)
486
487    void incrementTag(String packageName, String embedTag, boolean globalTagOrPackageTag)
488    {
489        // In 'EmbedTag' this reset back to 'EmbedTag' (see note above!)
490        Messager.setProcessorName("Stats");
491
492        if (    (this.LAST_USED_packageName == null)
493            ||  (! this.LAST_USED_packageName.equals(packageName)))
494        {
495            this.LAST_USED_packageName  = packageName;
496            this.LAST_USED_packageStats = this.packageStatsMap.get(packageName);
497
498            // This should never happen, but if it does, this exception is more meaningful than
499            // NullPointerException.  It isn't any better though!
500            //
501            // (IF NULL, THIS IS MY FAULT, NOT THEIR FAULT, and at the time of the writing of this
502            // code, THIS CANNOT HAPPEN.  HOWEVER, if something is changed, then this exception
503            // throw is more intelligent than NPE)
504
505            if (this.LAST_USED_packageStats == null)
506
507                Messager.assertFailGeneralPurpose(
508                    "The Package-Stats instance for Package [" + packageName + "] returned null " +
509                    "from the Global-Stats field 'packageStatsMap'\n" +
510                    "Processing Embed-Tag [" + BCYAN + embedTag + RESET + "], a " +
511                    (globalTagOrPackageTag ? "Global" : "Package-Local") + " Tag.",
512                    null
513                );
514        }
515
516        if (globalTagOrPackageTag)
517        {
518            Integer globalCount = this.globalTagsCount.get(embedTag);
519
520            // This should never happen, but if it does, this exception is more meaningful than
521            // NullPointerException.  It isn't any better though!
522            //
523            // SEE ABOVE COMMENT
524
525            if (globalCount == null)
526
527                Messager.assertFailGeneralPurpose(
528                    "The Global-Stats instance returned a null count, but these are all " +
529                    "supposed to have been initialized to zero.\n" +
530                    "Processing Embed-Tag [" + BCYAN + embedTag + RESET + "], a Global Tag.",
531                    null
532                );
533
534            this.globalTagsCount.put(embedTag, globalCount + 1);
535
536            // These are **ALWAYS NULL** the first time they are used.
537            Integer i = this.LAST_USED_packageStats.globalTagsCount.get(embedTag);
538
539            this.LAST_USED_packageStats.globalTagsCount.put(embedTag, (i == null) ? 1 : (i+1));
540        }
541        else
542        {
543            // These exception throws are being used more like Java 'assert' statements.  If an
544            // error occurs, it means that I changed something else, somplace else, and forgot
545            // about this part.  As of the time of the writing of this exception check, this
546            // field CAN NEVER BE NULL WHEN THIS LINE IS EXECUTED.
547
548            if (this.LAST_USED_packageStats.packageTagsCount == null)
549
550                Messager.assertFailGeneralPurpose(
551                    "While processing Embed-Tags for package [" + packageName + "]\n" +
552                    "The Package-Local Stats-Instance had a NULL-MAP reference for map " +
553                    "'packageTagsCount'.\n" +
554                    "Currently attempting to increment counter for (Package-Local) Embed-Tag " +
555                    "[" + BCYAN + embedTag + RESET + "].",
556                    null
557                );
558
559            Integer packageCount = this.LAST_USED_packageStats.packageTagsCount.get(embedTag);
560
561            // EXCEPTION-THROW COMMENT: SAME AS ABOVE.  This code is theoretically unreachable, 
562            // but every developer has been known to change something else, somewhere else, and
563            // at the same time forgetting how that change might affect THIS CODE (below)
564            //
565            // HERE, if 'packageCount' were null, this would BY MY FAULT, NOT THE USERS FAULT.
566
567            if (packageCount == null)
568            {
569                if (embedTag.equals(EmbedTag.RESERVED_EMBED_TAG_FILE_ID))
570                    this.LAST_USED_packageStats.packageTagsCount.put(embedTag, 1);
571
572                else Messager.assertFailGeneralPurpose(
573                    "While retrieving Embed-Tag Count Data for Package-Local Embed-Tag " +
574                    "[" + embedTag + "]\n" +
575                    "Located in Package [" + packageName + "]\n" +
576                    "The Embed-Tag-Count found in the packageTagsCount-Map had a null-Integer.  " +
577                    "But these are all initialized to zero.",
578                    null
579                );
580            }
581            else this.LAST_USED_packageStats.packageTagsCount.put(embedTag, packageCount + 1);
582        }
583    }
584
585
586    // ********************************************************************************************
587    // ********************************************************************************************
588    // Update Stats for a single File
589    // ********************************************************************************************
590    // ********************************************************************************************
591
592
593    // Increments all the counters by the value in the given parameters
594    // This is package-visible, because it really serves little purpose outside of this
595    // package.
596    //
597    // NOTE: 'jdhf' is only used for the "getMethods", "geFields" things.  It is not asked for
598    //       'fileVec'
599    //
600    // MESSAGER:
601    //  1) SETS:        processorName (on error only)
602    //  2) INVOKED-BY:  THIS METHOD IS ONLY INVOKED ONCE, FROM MainFilesProcesor
603    //  3) USES:        Only assertFailGeneralPurpose
604    //  4) RETURNS:     void method
605    //  5) EXPECTS:     FileName to be set
606    //  6) THROWS:      assertFailGeneralPurpose - no explicity throws
607
608    void run(
609            JavaSourceCodeFile jscf, JavaDocHTMLFile jdhf,
610            int numHLM, int numHLC, int numHLF, int numHLAE, int numHLEC,
611            int numHLD
612        )
613    {
614        Method[]            mArr = jscf.getMethods();
615        Constructor[]       cArr = jscf.getConstructors();
616        Field[]             fArr = jscf.getFields();
617        AnnotationElem[]    eArr = jscf.getAnnotationElems();
618        EnumConstant[]      xArr = jscf.getEnumConstants();
619
620        final Stats ps = this.packageStatsMap.get(jdhf.packageName);
621
622        // Currently, this has been verified to be impossible.  If something changes, a
623        // 'JavaDocError' throw is the best way to handle it.  Note that the 'cost' of doing
624        // this null-check is absolutely minimal.
625
626        if (ps == null)
627        {
628            Messager.setProcessorName("Stats");
629    
630            Messager.assertFailGeneralPurpose(
631                "While attempting to update the both the Global and the Package-Local " +
632                "Stats-Instance for JavaSourceCodeFile:\n    " +
633                '[' + BYELLOW + jscf.fileName + RESET + '\n' +
634                "The Package-Local Stats-Instance that was returned from the Package-Stats Map " +
635                "was null.",
636                null
637            );
638        }
639
640        // If this is an inner-class, then the number of lines in the class (and the number of
641        // bytes) will already have been counted when the Enclosing-Class was tallied.
642        // If this is an inner-class, just skip the counting of the lines/bytes for the class
643
644        if (! jdhf.isInner)
645        {
646            ps.numLines                     += jdhf.typeLineCount;
647            this.numLines                   += jdhf.typeLineCount;
648            ps.numBytes                     += jdhf.typeSizeChars;
649            this.numBytes                   += jdhf.typeSizeChars;
650        }
651
652        ps.numHiLitedDivs                   += numHLD;
653        this.numHiLitedDivs                 += numHLD;
654
655        ps.numMethods                       += mArr.length;
656        this.numMethods                     += mArr.length;
657        ps.numHiLitedMethods                += numHLM;
658        this.numHiLitedMethods              += numHLM;
659        ps.numDocumentedMethods             += jdhf.numMethods();
660        this.numDocumentedMethods           += jdhf.numMethods();
661
662        ps.numConstructors                  += cArr.length;
663        this.numConstructors                += cArr.length;
664        ps.numHiLitedConstructors           += numHLC;
665        this.numHiLitedConstructors         += numHLC;
666        ps.numDocumentedConstructors        += jdhf.numConstructors();
667        this.numDocumentedConstructors      += jdhf.numConstructors();
668
669        ps.numFields                        += fArr.length;
670        this.numFields                      += fArr.length;
671        ps.numHiLitedFields                 += numHLF;
672        this.numHiLitedFields               += numHLF;
673        ps.numDocumentedFields              += jdhf.numFields();
674        this.numDocumentedFields            += jdhf.numFields();
675
676        ps.numAnnotationElems               += eArr.length;
677        this.numAnnotationElems             += eArr.length;
678        ps.numHiLitedAnnotationElems        += numHLAE;
679        this.numHiLitedAnnotationElems      += numHLAE;
680        ps.numDocumentedAnnotationElems     += jdhf.numAnnotationElems();
681        this.numDocumentedAnnotationElems   += jdhf.numAnnotationElems();
682
683        ps.numEnumConstants                 += xArr.length;
684        this.numEnumConstants               += xArr.length;
685        ps.numHiLitedEnumConstants          += numHLEC;
686        this.numHiLitedEnumConstants        += numHLEC;
687        ps.numDocumentedEnumConstants       += jdhf.numEnumConstants();
688        this.numDocumentedEnumConstants     += jdhf.numEnumConstants();
689
690        for (Method m : mArr) m.getModifiers((String modifier) ->
691        {
692            switch (modifier)
693            {
694                case "static"       :   this.numStaticMethods++;
695                                        ps.numStaticMethods++;
696                                        break;
697                case "public"       :   this.numPublicMethods++;
698                                        ps.numPublicMethods++;
699                                        break;
700                case "protected"    :   this.numProtectedMethods++;
701                                        ps.numProtectedMethods++;
702                                        break;
703                case "private"      :   this.numPrivateMethods++;
704                                        ps.numPrivateMethods++;
705                                        break;
706                case "final"        :   this.numFinalMethods++;
707                                        ps.numFinalMethods++;
708                                        break;
709            }
710        });
711
712        for (Constructor c : cArr) c.getModifiers((String modifier) ->
713        {
714            switch (modifier)
715            {
716                case "public"       :   this.numPublicConstructors++;
717                                        ps.numPublicConstructors++;
718                                        break;
719                case "protected"    :   this.numProtectedConstructors++;
720                                        ps.numProtectedConstructors++;
721                                        break;
722                case "private"      :   this.numPrivateConstructors++;
723                                        ps.numPrivateConstructors++;
724                                        break;
725                case "final"        :   this.numFinalConstructors++;
726                                        ps.numFinalConstructors++;
727                                        break;
728            }
729        });
730
731        for (Field f : fArr) f.getModifiers((String modifier) ->
732        {
733            switch (modifier)
734            {
735                case "static"       :   this.numStaticFields++;
736                                        ps.numStaticFields++;
737                                        break;
738                case "public"       :   this.numPublicFields++;
739                                        ps.numPublicFields++;
740                                        break;
741                case "protected"    :   this.numProtectedFields++;
742                                        ps.numProtectedFields++;
743                                        break;
744                case "private"      :   this.numPrivateFields++;
745                                        ps.numPrivateFields++;
746                                        break;
747                case "final"        :   this.numFinalFields++;
748                                        ps.numFinalFields++;
749                                        break;
750                case "transient"    :   this.numTransientFields++;
751                                        ps.numTransientFields++;
752                                        break;
753                case "volatile"     :   this.numVolatileFields++;
754                                        ps.numVolatileFields++;
755                                        break;
756            }
757        });
758    }
759
760
761    // ********************************************************************************************
762    // ********************************************************************************************
763    // To String
764    // ********************************************************************************************
765    // ********************************************************************************************
766
767
768    /**
769     * Generates a {@code String} that enapsulates all of the counters / running-totals inside
770     * this data statistic class.
771     * 
772     * @return A {@code String} representation of this class.  Only includes statistics about
773     * use of methods, constructors, fields etc...  <B>DOES NOT INCLUDE</B> statistics regarding
774     * the use of the {@code <EMBED CLASS='external-html' ...>} tags.
775     */
776    public String toString()
777    {
778        StringBuilder sb = new StringBuilder();
779
780        for (String packageName : packageStatsMap.keySet())
781            sb.append(
782                "Stats for Package: [" + BCYAN + packageName + RESET + "]:\n\n" +
783                StrIndent.indent(toStringINTERNAL(packageStatsMap.get(packageName)), 4) + '\n'
784            );
785
786        sb.append("UPGADE / BUILD TOTAL:\n\n" + toStringINTERNAL(this));
787
788        return sb.toString();
789    }
790
791    private static String toStringINTERNAL(Stats s)
792    {
793        return
794            StringParse.rightSpacePad("" + StringParse.commas(s.numLines), 12)                       + "Total Lines of Source Code\n" +
795            StringParse.rightSpacePad("" + StringParse.commas(s.numBytes), 12)                       + "Total Bytes of Source Code\n" +
796            '\n' +
797            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedDivs), 12)                 + "HiLited DIV Tags\n" +
798            '\n' +
799            StringParse.rightSpacePad("" + StringParse.commas(s.numMethods), 12)                     + "Source Total Methods\n" +
800            StringParse.rightSpacePad("" + StringParse.commas(s.numFields), 12)                      + "Source Total Fields\n" +
801            StringParse.rightSpacePad("" + StringParse.commas(s.numConstructors), 12)                + "Source Total Constructors\n" +
802            StringParse.rightSpacePad("" + StringParse.commas(s.numAnnotationElems), 12)             + "Source Total Annotation Elements\n" +
803            StringParse.rightSpacePad("" + StringParse.commas(s.numEnumConstants), 12)               + "Source Total Enumeration Constants\n" +
804            '\n' +
805            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedMethods), 12)              + "Method Bodies HiLited\n" +
806            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedFields), 12)               + "Fields Declarations HiLited\n" +
807            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedConstructors), 12)         + "Constructors Bodies HiLited\n" +
808            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedAnnotationElems), 12)      + "Annotation Elements HiLited\n" +
809            StringParse.rightSpacePad("" + StringParse.commas(s.numHiLitedEnumConstants), 12)        + "Enumeration Constants HiLited\n" +
810            '\n' +
811            StringParse.rightSpacePad("" + StringParse.commas(s.numDocumentedMethods), 12)           + "JavaDoc Documented Methods\n" +
812            StringParse.rightSpacePad("" + StringParse.commas(s.numDocumentedFields), 12)            + "JavaDoc Documented Fields\n" +
813            StringParse.rightSpacePad("" + StringParse.commas(s.numDocumentedConstructors), 12)      + "JavaDoc Documented Constructors\n" +
814            StringParse.rightSpacePad("" + StringParse.commas(s.numDocumentedAnnotationElems), 12)   + "JavaDoc Documented Annotation Elements\n" +
815            StringParse.rightSpacePad("" + StringParse.commas(s.numDocumentedEnumConstants), 12)     + "JavaDoc Documented Enumeration Constants\n" +
816            '\n' +
817            StringParse.rightSpacePad("" + StringParse.commas(s.numStaticMethods), 12)               + "Static Methods\n" +
818            StringParse.rightSpacePad("" + StringParse.commas(s.numStaticFields), 12)                + "Static Fields\n" +
819            '\n' +
820            StringParse.rightSpacePad("" + StringParse.commas(s.numFinalMethods), 12)                + "Final Methods\n" +
821            StringParse.rightSpacePad("" + StringParse.commas(s.numFinalFields), 12)                 + "Final Fields\n" +
822            StringParse.rightSpacePad("" + StringParse.commas(s.numFinalConstructors), 12)           + "Final Constructors\n" +
823            '\n' +
824            StringParse.rightSpacePad("" + StringParse.commas(s.numPublicMethods), 12)               + "Public Methods\n" +
825            StringParse.rightSpacePad("" + StringParse.commas(s.numPublicFields), 12)                + "Public Fields\n" +
826            StringParse.rightSpacePad("" + StringParse.commas(s.numPublicConstructors), 12)          + "Public Constructors\n" +
827            '\n' +
828            StringParse.rightSpacePad("" + StringParse.commas(s.numProtectedMethods), 12)            + "Protected Methods\n" +
829            StringParse.rightSpacePad("" + StringParse.commas(s.numProtectedFields), 12)             + "Protected Fields\n" +
830            StringParse.rightSpacePad("" + StringParse.commas(s.numProtectedConstructors), 12)       + "Protected Constructors\n" +
831            '\n' +
832            StringParse.rightSpacePad("" + StringParse.commas(s.numPrivateMethods), 12)              + "Private Methods\n" +
833            StringParse.rightSpacePad("" + StringParse.commas(s.numPrivateFields), 12)               + "Private Fields\n" +
834            StringParse.rightSpacePad("" + StringParse.commas(s.numPrivateConstructors), 12)         + "Private Constructors\n" +
835            '\n' +
836            StringParse.rightSpacePad("" + StringParse.commas(s.numTransientFields), 12)             + "Transient Fields\n" +
837            StringParse.rightSpacePad("" + StringParse.commas(s.numVolatileFields), 12)              + "Volatile Fields\n";
838    }
839
840
841    // ********************************************************************************************
842    // ********************************************************************************************
843    // Inserting Link into JavaDoc Directory MAIN-OVERVIEW FRAMES
844    // ********************************************************************************************
845    // ********************************************************************************************
846
847
848    private static final String HEADER =
849        "<HTML>\n<HEAD>\n" +
850        "<TITLE>Statistics</TITLE>\n" +
851        "<LINK rel='icon' type='image/jpg' href='favicon.jpg' />\n" +
852        "<LINK rel='stylesheet' type='text/css' href='JavaDoc.css' />\n" +
853        "</HEAD>\n" +
854        "<BODY CLASS=STATS>\n";
855
856    private static final String FOOTER = "\n</BODY>\n</HTML>\n";
857
858    // Writes a Java-Doc Viewable HTML File explaining the Statistics
859    // RETURN This shall return TRUE when the file was successfully written
860    //
861    // MESSAGER
862    //  1) INVOKED-BY: Only called once in Upgrade.upgrade, No Where Else
863    //  2) SETS: processorName, fileName
864    //  3) USES: println, errorContinue
865    //  4) RETURNS: FALSE if there was an error
866
867    boolean saveStatsHTMLFile(String saveFileDirectory)
868    {
869        Messager.println("\nWriting Statistics to Root Java Doc Directory.");
870
871        StringBuilder html = new StringBuilder();
872
873        html.append(HEADER);
874
875        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
876        // Regular Stats - Methods, Fields, etc... - (almost identical to: 'toString')
877        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
878
879        html.append("<TABLE CLASS=STATS>\n");
880
881        for (Map.Entry<String, Stats> packageStats : packageStatsMap.entrySet())
882        {
883            // Method, Constructor, Field, Counts  etc... - COUNTS FOR EACH PACKAGE
884            html.append(
885                "\n\n\t<TR><TD COLSPAN=3>&nbsp;<BR /><BR /><BR /></TD></TR>\n" +
886                "\t<TR><TH ID='" +
887                packageStats.getKey() +  // Using the Package-Name as the HTML-ID for finding it
888                "' COLSPAN=3>\n\t\tStats for Package: <SPAN CLASS=PNSTATS>" +
889                packageStats.getKey() +  // Package-Name (as String)
890                "</SPAN></TH></TR>\n" +
891                toHTML_INTERNAL(packageStats.getValue()) + "\n\n" // Package-Stats (as Stats)
892            );
893
894            // This was broken up into a separate method becuse it is so long
895            append_one_packages_embed_tag_statistics(packageStats, html);
896        }
897
898
899        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
900        // Method, Constructor, Field etc... - COUNT-TOTALS FOR COMPLETE PROJECT
901        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
902
903        html.append(
904            "\n\n\n\t<TR><TD COLSPAN=3>&nbsp;<BR /><BR /><BR /></TD></TR>\n" +
905            "\n\t<TR><TH COLSPAN=3><SPAN CLASS=PNTSTATS>UPGADE / BUILD TOTAL:</SPAN></TH></TR>" +
906            toHTML_INTERNAL(this)
907        );
908
909    
910        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
911        // Embed-Tag Count Totals ... - FOR COMPLETE PROJECT
912        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
913
914        html.append(
915            "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n" +
916            "\n\n\t<TR><TH COLSPAN=3><SPAN CLASS=PNTSTATS>Complete Upgrade Totals:" +
917            "</SPAN></TH></TR>\n"
918        );
919
920        if (this.globalTagsMap != null)
921            // NO MESSAGER, NO THROWS
922            tagCountToHTML(
923                globalTagsCount, this.globalTagsMap, html,
924                true,   // YES, Print the Zero-Count
925                true    // This is the GLOBAL TagsMap Count
926            );
927
928        html.append("</TABLE>\n");
929
930
931        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
932        // Write File, Exit
933        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
934
935        html.append(FOOTER);
936
937        String saveFileName = saveFileDirectory + STATS_HTML_FILENAME;
938
939        try
940            { FileRW.writeFile(html, saveFileName); }
941
942        catch (Exception ioe)
943        {
944            Messager.errorContinue(
945                ioe,
946                "Failed to Write Stats.html - Links to Stats in Overview Pages will be broken."
947            );
948
949            return false;
950        }
951
952        if (Messager.isVerbose())
953            Messager.println("Wrote File: " + BYELLOW + saveFileName + RESET);
954
955        return true;
956    }
957
958    // This method was extracted out of the loop and turned into an independent method.
959    // It looks better this way.  That's all.
960    private void append_one_packages_embed_tag_statistics
961        (Map.Entry<String, Stats> packageStats, StringBuilder html)
962    {
963        Stats s = packageStats.getValue();
964
965        if (Messager.isVerbose())
966            Messager.println("Printing Stats to HTML for Package: " + packageStats.getKey());
967
968        // Absolute number of "Package-Local Embed Tags" are used - regardless of whether there
969        // were any "Package-Local Embed Tags" even defined.
970        int nPkgTags = (s.packageTagsCount == null) ? 0 : s.packageTagsCount.size();
971
972        // Absolute number for "Package-Local Use of Global Embed Tags"
973        int nGblTags = (s.globalTagsCount == null) ? 0 : s.globalTagsCount.size();
974
975        // IF A SPECIFIC PACKAGE DOES NOT USE <EMBED CLASS='external-html'> TAGS, SKIP IT.
976        if ((nPkgTags == 0) && (nGblTags == 0)) return;
977
978        html.append(
979            "\n\n\t<TR><TH COLSPAN=3>Embed Tag FILE-ID Counts for Package: " +
980            "<SPAN CLASS=PNSTATS>" + packageStats.getKey() + "</SPAN></TH></TR>\n"
981        );
982
983        if (nGblTags > 0) // Package-Local USE OF *GLOBAL Embed-Tags
984        {
985            html.append(
986                "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n" +
987                "\n\t<TR><TD COLSPAN=3><B>Global &lt;EMBED&gt; Tags Used:</B></TD></TR>\n"
988            );
989
990            // NO MESSAGER, NO THROWS
991            tagCountToHTML(
992                s.globalTagsCount, this.globalTagsMap, html,
993                false,  // Don't mention zero-counts (there cannot be any, anyway)
994                        // Since this is "Package Use of Global-Tags", it's not important
995                        //
996                true    // This tells it that these are global-counts, so it prints it properly
997            );
998        }
999
1000        if (nPkgTags > 0) // Package-Local Tags
1001        {
1002            html.append(
1003                "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n" +
1004                "\n\t<TR><TD COLSPAN=3><B>Package-Local &lt;EMBED&gt; Tags Used:</B></TD></TR>\n"
1005            );
1006
1007            // NO MESSAGER, NO THROWS
1008            tagCountToHTML(
1009                s.packageTagsCount, s.packageTagsMap, html,
1010                true,   // Print the zero-counts, These are Package-Tags, so if the user didn't
1011                        // did not use some tags, put a notice about it.
1012                        //
1013                false   // This tells it that these are local-counts, so it prints it properly
1014            );
1015        }
1016    }
1017
1018
1019    // ********************************************************************************************
1020    // ********************************************************************************************
1021    // Generating Stats HTML Files
1022    // ********************************************************************************************
1023    // ********************************************************************************************
1024
1025
1026    // This merely builds an HTML table out of an instance of Stats
1027    // NOTE: It **DOES NOT** include the "Package-Level" stats Tables.
1028    //       That is done recursively.
1029    private static String toHTML_INTERNAL(Stats s)
1030    {
1031        return
1032            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1033
1034            "\t<TR><TD>" + StringParse.commas(s.numLines)                       + "</TD><TD COLSPAN=2>Total Lines of Source Code</TD></TR>\n" +
1035            "\t<TR><TD>" + StringParse.commas(s.numBytes)                       + "</TD><TD COLSPAN=2>Total Bytes of Source Code</TD></TR>\n" +
1036            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1037
1038            "\t<TR><TD>" + StringParse.commas(s.numHiLitedDivs)                 + "</TD><TD COLSPAN=2>HiLited DIV Tags</TD></TR>\n" +
1039            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1040
1041            "\t<TR><TD>" + StringParse.commas(s.numMethods)                     + "</TD><TD COLSPAN=2>Source Total Methods</TD></TR>\n" +
1042            "\t<TR><TD>" + StringParse.commas(s.numFields)                      + "</TD><TD COLSPAN=2>Source Total Fields</TD></TR>\n" +
1043            "\t<TR><TD>" + StringParse.commas(s.numConstructors)                + "</TD><TD COLSPAN=2>Source Total Constructors</TD></TR>\n" +
1044            "\t<TR><TD>" + StringParse.commas(s.numAnnotationElems)             + "</TD><TD COLSPAN=2>Source Total Annotation Elements</TD></TR>\n" +
1045            "\t<TR><TD>" + StringParse.commas(s.numEnumConstants)               + "</TD><TD COLSPAN=2>Source Total Enumeration Constants</TD></TR>\n" +
1046            "\t<TR><TD COLSPAN=3>&nbsp;</TD>\n" +
1047
1048            "\t<TR><TD>" + StringParse.commas(s.numHiLitedMethods)              + "</TD><TD COLSPAN=2>Method Bodies HiLited</TD></TR>\n" +
1049            "\t<TR><TD>" + StringParse.commas(s.numHiLitedFields)               + "</TD><TD COLSPAN=2>Fields Declarations HiLited</TD></TR>\n" +
1050            "\t<TR><TD>" + StringParse.commas(s.numHiLitedConstructors)         + "</TD><TD COLSPAN=2>Constructors Bodies HiLited</TD></TR>\n" +
1051            "\t<TR><TD>" + StringParse.commas(s.numHiLitedAnnotationElems)      + "</TD><TD COLSPAN=2>Annotation Elements HiLited</TD></TR>\n" +
1052            "\t<TR><TD>" + StringParse.commas(s.numHiLitedEnumConstants)        + "</TD><TD COLSPAN=2>Enumeration Constants HiLited</TD></TR>\n" +
1053            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1054
1055            "\t<TR><TD>" + StringParse.commas(s.numDocumentedMethods)           + "</TD><TD COLSPAN=2>JavaDoc Documented Methods</TD></TR>\n" +
1056            "\t<TR><TD>" + StringParse.commas(s.numDocumentedFields)            + "</TD><TD COLSPAN=2>JavaDoc Documented Fields</TD></TR>\n" +
1057            "\t<TR><TD>" + StringParse.commas(s.numDocumentedConstructors)      + "</TD><TD COLSPAN=2>JavaDoc Documented Constructors</TD></TR>\n" +
1058            "\t<TR><TD>" + StringParse.commas(s.numDocumentedAnnotationElems)   + "</TD><TD COLSPAN=2>JavaDoc Documented Annotation Elements</TD></TR>\n" +
1059            "\t<TR><TD>" + StringParse.commas(s.numDocumentedEnumConstants)     + "</TD><TD COLSPAN=2>JavaDoc Documented Enumeration Constants</TD></TR>\n" +
1060            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1061
1062            "\t<TR><TD>" + StringParse.commas(s.numStaticMethods)               + "</TD><TD COLSPAN=2>Static Methods</TD></TR>\n" +
1063            "\t<TR><TD>" + StringParse.commas(s.numStaticFields)                + "</TD><TD COLSPAN=2>Static Fields</TD></TR>\n" +
1064            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1065
1066            "\t<TR><TD>" + StringParse.commas(s.numFinalMethods)                + "</TD><TD COLSPAN=2>Final Methods</TD></TR>\n" +
1067            "\t<TR><TD>" + StringParse.commas(s.numFinalFields)                 + "</TD><TD COLSPAN=2>Final Fields</TD></TR>\n" +
1068            "\t<TR><TD>" + StringParse.commas(s.numFinalConstructors)           + "</TD><TD COLSPAN=2>Final Constructors</TD></TR>\n" +
1069            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1070
1071            "\t<TR><TD>" + StringParse.commas(s.numPublicMethods)               + "</TD><TD COLSPAN=2>Public Methods</TD></TR>\n" +
1072            "\t<TR><TD>" + StringParse.commas(s.numPublicFields)                + "</TD><TD COLSPAN=2>Public Fields</TD></TR>\n" +
1073            "\t<TR><TD>" + StringParse.commas(s.numPublicConstructors)          + "</TD><TD COLSPAN=2>Public Constructors</TD></TR>\n" +
1074            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1075
1076            "\t<TR><TD>" + StringParse.commas(s.numProtectedMethods)            + "</TD><TD COLSPAN=2>Protected Methods</TD></TR>\n" +
1077            "\t<TR><TD>" + StringParse.commas(s.numProtectedFields)             + "</TD><TD COLSPAN=2>Protected Fields</TD></TR>\n" +
1078            "\t<TR><TD>" + StringParse.commas(s.numProtectedConstructors)       + "</TD><TD COLSPAN=2>Protected Constructors</TD></TR>\n" +
1079            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1080
1081            "\t<TR><TD>" + StringParse.commas(s.numPrivateMethods)              + "</TD><TD COLSPAN=2>Private Methods</TD></TR>\n" +
1082            "\t<TR><TD>" + StringParse.commas(s.numPrivateFields)               + "</TD><TD COLSPAN=2>Private Fields</TD></TR>\n" +
1083            "\t<TR><TD>" + StringParse.commas(s.numPrivateConstructors)         + "</TD><TD COLSPAN=2>Private Constructors</TD></TR>\n" +
1084            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n" +
1085
1086            "\t<TR><TD>" + StringParse.commas(s.numTransientFields)             + "</TD><TD COLSPAN=2>Transient Fields</TD></TR>\n" +
1087            "\t<TR><TD>" + StringParse.commas(s.numVolatileFields)              + "</TD><TD COLSPAN=2>Volatile Fields</TD></TR>\n" +
1088            "\t<TR CLASS=BLANK><TD COLSPAN=3>&nbsp;</TD>\n";
1089    }
1090
1091    // This one works slightly differently than the previous "toHTML" function
1092    // It places the appended text inside the passed StringBuilder
1093    //
1094    // NO MESSAGER, NO THROWS
1095
1096    private static void tagCountToHTML(
1097            Map<String, Integer>    embedTagsCount,
1098            Map<String, String>     embedTagsMap,
1099            StringBuilder           sb,
1100            boolean                 printZeros,
1101            boolean                 globalOrLocal
1102        )
1103    {
1104        StringBuilder zerosCountSB = new StringBuilder();
1105
1106        sb.append("\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n");
1107
1108        for (Map.Entry<String, String> embedTag : embedTagsMap.entrySet())
1109        {
1110            Integer count = embedTagsCount.get(embedTag.getKey());
1111
1112            if (count == null) continue;
1113
1114            String s =
1115                "\t<TR>" +
1116                "<TD>" + StringParse.commas(count) + "</TD>" +
1117                "<TD>" + embedTag.getKey() + "</TD>" +
1118                "<TD>" + embedTag.getValue() + "</TD>" +
1119                "</TR>\n";
1120
1121            if (count > 0) sb.append(s);
1122
1123            if (printZeros && (count == 0)) zerosCountSB.append(s);
1124        }
1125
1126        sb.append("\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n");
1127
1128        if (printZeros && (zerosCountSB.length() > 0))
1129
1130            sb.append(
1131                "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n" +
1132                "\n\t<TR><TD COLSPAN=3><B>Unused " +
1133                    (globalOrLocal ? "Global" : "Package-Local ") +
1134                    "&lt;EMBED&gt; Tags:</B></TD></TR>\n" +
1135                "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n" +
1136                zerosCountSB.toString() +
1137                "\n\t<TR><TD COLSPAN=3>&nbsp;</TD></TR>\n"
1138            );
1139    }
1140
1141
1142    // ********************************************************************************************
1143    // ********************************************************************************************
1144    // Generating Stats HTML Files
1145    // ********************************************************************************************
1146    // ********************************************************************************************
1147
1148
1149    // This is the "Stats" button that's inserted into the pages
1150    private static final Vector<HTMLNode> nodesToInsert =
1151        HTMLPage.getPageTokens("<LI><A>Stats</A></LI>\n", false);
1152
1153    // In the above defined Vector, the <LI> has an HTML Anchor <A> at Vector-index 1.
1154    private static final int ANCHOR_POS = 1;
1155
1156    // Used by: "ExtraFilesProcessor"
1157    //
1158    // MESSAGER:
1159    //  1) SETS:        processorName
1160    //  2) RETURN:      'false' if Messager used for warning
1161    //  3) CALLS:       warning *ONLY*
1162    //  4) INVOKED-BY:  *ONCE* ExtraFilesProcessor
1163    //  5) EXPECTS:     fileName to be set.
1164
1165    static boolean addStatsButton(Vector<HTMLNode> page, String dotDots, String packageName)
1166    {
1167        Messager.setProcessorName("Stats");
1168
1169        AVT avt =
1170            AVT.cmp("class", TextComparitor.C, "navList").and(
1171            AVT.cmp("title", TextComparitor.EQ, "Navigation"));
1172
1173        Vector<SubSection> navMenus = InnerTagPeekInclusive.all(page, avt, "ul");
1174
1175        if (navMenus.size() < 2)
1176        {
1177            Messager.warning("No Navigtion Menus Found, not adding a 'Stats.html' Link.");
1178            return false; // This boolean indicates that the Messager *WAS* used.
1179        }
1180
1181        SubSection topNav = navMenus.elementAt(0);
1182        SubSection tailNav = navMenus.elementAt(1);
1183
1184        // MESSAGER:
1185        //  1) SETS:        Processor Name
1186        //  2) RETURN:      'false' if the Messager *WAS* used on warning
1187        //  3) INVOKES:     warning *ONLY*
1188        //  4) INVOKED-BY:  *TWICE* MainFilesProcessor, and THIS INVOKATION RIGHT-HERE
1189        //  5) EXPECTS:     File-Name to be set.
1190        //  6) THROWS:      NO THROW STATEMENTS
1191
1192        if (! addStatsButton(topNav.html, tailNav.html, dotDots, packageName)) return false;
1193
1194        ReplaceNodes.r(page, topNav);
1195        ReplaceNodes.r(page, tailNav);
1196
1197        return true;
1198    }
1199
1200    // Used by: "MainFilesProcessor"
1201    // Inserts a button into the Navigation Bar on a Java Doc HTML Page.
1202    //
1203    // MESSAGER:
1204    //  1) SETS:        Processor Name
1205    //  2) RETURN:      'false' if the Messager *WAS* used on warning
1206    //  3) INVOKES:     warning *ONLY*
1207    //  4) INVOKED-BY:  *TWICE* - MainFilesProcessor, and method directly-above
1208    //  5) EXPECTS:     File-Name to be set.
1209    //  6) THROWS:      NO THROW STATEMENTS
1210
1211    @SuppressWarnings("unchecked") // The clone invocation
1212    static boolean addStatsButton(
1213            Vector<HTMLNode> navBarTop, Vector<HTMLNode> navBarBottom,
1214            String dotDots, String packageName
1215        )
1216    {
1217        Messager.setProcessorName("Stats");
1218
1219        // Find: <ul class="navList" title="Navigation">
1220        AVT avt =
1221            AVT.cmp("class", TextComparitor.C, "navList").and(
1222            AVT.cmp("title", TextComparitor.EQ, "Navigation"));
1223
1224        // Get the Pertinent Navigator-Menu.  It is a sub-part of the overall Navigation-Bar
1225        // The Stats Button is added to the first Navigation-List <UL> of both the bottom
1226        // and top Navigation-Bar.
1227
1228        DotPair topDP       = InnerTagFindInclusive.first(navBarTop, avt, "ul");
1229        DotPair bottomDP    = InnerTagFindInclusive.first(navBarBottom, avt, "ul");
1230
1231        // Print some pointless warnings.  This will one day break.  Warning messages are better
1232        // than Unknown-Exceptions.  Not everybody uses the Navigation-Menus, and what will
1233        // happen once a user runs this without them is currently unknown.
1234
1235        boolean topNull     = topDP == null;
1236        boolean tailNull    = bottomDP == null;
1237
1238        if (topNull && tailNull)
1239        {
1240            Messager.warning("This page does not have any Navigatin Menus");
1241            return false;
1242        }
1243
1244        else if (topNull || tailNull)
1245        {
1246            if (topNull) Messager.warning("Page does not have a Top Navigation Menu.");
1247            if (tailNull) Messager.warning("Page does not have a Tail Navigation Menu.");
1248            return false;
1249        }
1250
1251        // Clone the STATIC-FINAL 'nodesToInsert' Vector.
1252        Vector<HTMLNode> v = (Vector<HTMLNode>) nodesToInsert.clone();
1253
1254        // The HTML <A HREF=...> elemet that needs the RELATIVE-PATH URL w/ 'dotDots'
1255        TagNode anchor = (TagNode) nodesToInsert.elementAt(ANCHOR_POS);
1256
1257        // Set the HREF for the anchor-url link
1258        anchor = anchor.setAV("HREF", dotDots + "Stats.html#" + packageName, SD.SingleQuotes);
1259
1260        // Replace the old HTML Anchor Element with the updated one having the
1261        // relative path String to the base Java Doc directory.
1262
1263        v.setElementAt(anchor, ANCHOR_POS);
1264
1265        // Insert the updated navigator-menu item into the page, AS THE LAST ELEMENT 
1266        // of the menu (beginning at the node JUST-BEFORE the one located at navMenu.end)
1267
1268        /*if (! topNull)  */ navBarTop.addAll(topDP.end, v);
1269        /*if (! tailNull) */ navBarBottom.addAll(bottomDP.end, v);
1270
1271        return true;
1272    }
1273}