001package Torello.JavaDoc;
002
003import Torello.HTML.*;
004import Torello.HTML.NodeSearch.*;
005import Torello.JDUInternal.HTMLProcessors.Other.*;
006import Torello.JDUInternal.ParseHTML.*;
007import Torello.Java.Additional.*;
008import Torello.Java.*;
009
010import Torello.Java.ReadOnly.ReadOnlyArrayList;
011import Torello.Java.ReadOnly.ReadOnlyList;
012
013import static Torello.Java.C.*;
014
015import Torello.JDUInternal.GeneralPurpose.Messager;
016
017import Torello.JDUInternal.ParseJavaSource.JavaSourceCodeFile;
018
019import Torello.JDUInternal.DataClasses.MainLoopData.JDHFHeaderFacts;
020
021import Torello.JDUInternal.DataClasses.ClassUpgradeData.UpgradePredicates;
022import Torello.JDUInternal.DataClasses.ClassUpgradeData.PathsAndTypes;
023
024import java.util.*;
025import java.util.regex.*;
026import java.util.stream.*;
027
028import java.io.File;
029import java.util.function.Predicate;
030import java.util.function.Function;
031
032/**
033 * Retains all information parsed from a <CODE>'&#46;html'</CODE> Java-Doc web-page, and borrows
034 * any missing information that was found in the <CODE>'&#46;java'</CODE> source-code file; note
035 * that an instance-reference of this class may be rerieved, and used, to further change a Java
036 * Doc page by registering a visitor-handler with the configuration class {@link Upgrade} by
037 * calling <B>{@link Upgrade#setExtraTasks(Consumer)}</B>.
038 * 
039 * <EMBED CLASS='external-html' DATA-FILE-ID=PROG_MOD_HTML>
040 * <EMBED CLASS='external-html' DATA-FILE-ID=JD_HTML_F>
041 * 
042 * @see JavaSourceCodeFile
043 */
044@JDHeaderBackgroundImg(EmbedTagFileID="REFLECTION_HTML_CLASS")
045public final class JavaDocHTMLFile extends ParsedFile implements java.io.Serializable
046{
047    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID>  */
048    public static final long serialVersionUID = 1;
049
050
051    // ********************************************************************************************
052    // ********************************************************************************************
053    // Primary (Final) Fields
054    // ********************************************************************************************
055    // ********************************************************************************************
056
057
058    /**
059     * This provides the relative path-{@code String} from {@code 'this'} Java Doc generated
060     * {@code '.html'} File to the root Java Doc Directory.
061     */
062    public final RelativePathStr dotDots;
063
064    // The HTML Vector for a Java Doc web-page
065    private final Vector<HTMLNode> fileVec;
066
067    // This is where the 'updated-vector' is saved after the changes have been recommitted.
068    private Vector<HTMLNode> updatedFileVec = null;
069
070    /**
071     * The HTML that occurs directly above the Summary-Tables is the header.  The HTML that is
072     * located below the Detail-Entries is the footer.
073     */
074    public final HeaderFooterHTML headerFooter;
075
076    /**
077     * This is the File-{@code URL} to use if a need to link to the corresponding
078     * {@code "/src-html/"} file is necessary.
079     * 
080     * <BR /><BR />This is a <B STYLE='color: red;'>relative</B>-URL that contains the requisite
081     * number of 'dot-dots' to reach the file from the location where this Java Doc HTML File is
082     * located.
083     */
084    public final String srcAsHTMLFileURL;
085
086    /**
087     * This is the File-{@code URL} to use if a need to link to the corresponding
088     * {@code "/hilite-files/"} file is necessary.
089     * 
090     * <BR /><BR />This is a <B STYLE='color: red;'>relative</B>-URL that is relative to the file
091     * from the location where this Java Doc HTML File is located.  Specifically, this
092     * {@code String} begins with the text {@code "/hilite-files/"}, followed by the type-name,
093     * and ending with the extension {@code ".java.html"}
094     */
095    public final String hiLitedSrcFileURL;
096
097
098    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
099    // The HTML Details as Vector<ReflHTML<?>>
100    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
101
102    /**
103     * This is the list of all constructors in the "Constructor Details", stored as
104     * Reflection-HTML instances
105     */
106    public final ReadOnlyList<ReflHTML<Constructor>> allConstructorDetails;
107
108    /**
109     * This is the list of all fields in the "Field Details", stored as Reflection-HTML
110     * instances
111     */
112    public final ReadOnlyList<ReflHTML<Field>> allFieldDetails;
113
114    /**
115     * This is the list of all methods in the "Method Details", stored as Reflection-HTML
116     * instances
117     */
118    public final ReadOnlyList<ReflHTML<Method>> allMethodDetails;
119
120    /**
121     * This is the list of all constants in the "Enumerated Constant Details", stored as
122     * Reflection-HTML instances
123     */
124    public final ReadOnlyList<ReflHTML<EnumConstant>> allECDetails;
125
126    /**
127     * This is the list of all elements in the "Annotation Element Details", stored as
128     * Reflection-HTML instances
129     */
130    public final ReadOnlyList<ReflHTML<AnnotationElem>> allAEDetails;
131
132
133    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
134    // The HTML Summaries as SummaryTableHTML
135    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
136
137    /** The HTML for a Method Summary */
138    public final SummaryTableHTML<Method> methodSummaryTable;
139
140    /** The HTML for a Field Summary Table */
141    public final SummaryTableHTML<Field> fieldSummaryTable;
142
143    /** The HTML for a Constructor Summary Table */
144    public final SummaryTableHTML<Constructor> constructorSummaryTable;
145
146    /** The HTML for an Enum-Constant Summary Table */
147    public final SummaryTableHTML<EnumConstant> ecSummaryTable;
148
149    /** The HTML for an Optional Annotation Element Summary Table */
150    public final SummaryTableHTML<AnnotationElem> oaeSummaryTable;
151
152    /** The HTML for a Required Annotation Element Summary Table */
153    public final SummaryTableHTML<AnnotationElem> raeSummaryTable;
154
155    /** The HTML for a Nested-Class (Inner-Class) Summary Table */
156    public final SummaryTableHTML<NestedType> ntSummaryTable;
157
158    /** all non-null {@link SummaryTableHTML} instances */
159    @SuppressWarnings("rawtypes")
160    private final Vector<SummaryTableHTML> allNonNullSummaryTables;
161
162
163    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
164    // Booleans for remembering whether a Details Section was removed completely
165    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
166
167    /** Identifies if this Java Doc HTML Page has had it's Method Details Removed */
168    public final boolean methodDetailsRemoved;
169
170    /** Identifies if this Java Doc HTML Page has had it's Constructor Details Removed */
171    public final boolean constructorDetailsRemoved;
172
173    /** Identifies if this Java Doc HTML Page has had it's Field Details Removed */
174    public final boolean fieldDetailsRemoved;
175
176    /** Identifies if this Java Doc HTML Page has had it's Enumeration Constant Details Removed */
177    public final boolean ecDetailsRemoved;
178
179    /** Identifies if this Java Doc HTML Page has had it's Annotation-Element Details Removed */
180    public final boolean aeDetailsRemoved;
181
182
183    // ********************************************************************************************
184    // ********************************************************************************************
185    // Getters: Summaries
186    // ********************************************************************************************
187    // ********************************************************************************************
188
189
190    /**
191     * An {@code Iterator} that iterates the Summary Tables defined on this page.
192     * 
193     * @return An Instance of {@code Iterator<SummaryTableHTML>}.
194     * 
195     * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> There is a <B>raw-type</B> used by the 
196     * {@code Iterator} that is returned.  If this method is invoked, it will either generate
197     * compiler warnings, or the @{@code SuppressWarnings("rawtypes")} annotation will need to be
198     * applied (and, likely, the suppressing of {@code "unchecked"} warnings will also have to be
199     * applied eventually)
200     */
201    @SuppressWarnings("rawtypes")
202    public Iterator<SummaryTableHTML> allNonNullSummaryTables()
203    { return new RemoveUnsupportedIterator<>(allNonNullSummaryTables.iterator()); }
204
205    /**
206     * An {@code Stream} of the Summary Tables defined on this page.
207     * 
208     * @return An Instance of {@code Stream<SummaryTableHTML>}.
209     * 
210     * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> There is a <B>raw-type</B> used by the 
211     * {@code Stream} that is returned.  If this method is invoked, it will either generate
212     * compiler warnings, or the @{@code SuppressWarnings("rawtypes")} annotation will need to be
213     * applied (and, likely, the suppressing of {@code "unchecked"} warnings will also have to be
214     * applied eventually)
215     */
216    @SuppressWarnings("rawtypes")
217    public Stream<SummaryTableHTML> allNonNullSummaryTablesStream()
218    { return allNonNullSummaryTables.stream(); }
219
220
221    // ********************************************************************************************
222    // ********************************************************************************************
223    // Find Methods: Methods that accept a String / int
224    // ********************************************************************************************
225    // ********************************************************************************************
226
227
228    /**
229     * Returns a list as a {@code java.util.stream.Stream} of all Reflected-HTML-{@link Method}
230     * instances that have a name equal to {@code 'methodName'}.
231     * 
232     * @param methodName The name of the method being searched for.
233     * 
234     * @return A Java Stream containing all {@link Method}-{@link ReflHTML} instances that match
235     * the provided {@code 'methodName'} criteria.
236     */
237    public Stream<ReflHTML<Method>> findMethodHTML(String methodName)
238    {
239        return allMethodDetails
240            .stream()
241            .filter((ReflHTML<Method> refl) -> refl.entity.name.equals(methodName));
242    }
243
244    /**
245     * Returns a list as a {@code java.util.stream.Stream} of all Reflected-HTML-{@link Method}
246     * instances that have the specified number of parameters.
247     * 
248     * @param numParameters The number of parameters contained by the {@link Method} being searched
249     * for.
250     * 
251     * @return A Java Stream containing all {@link Method}-{@link ReflHTML} instances that match
252     * the provided {@code 'numParameters'} criteria.
253     */
254    public Stream<ReflHTML<Method>> findMethodHTML(int numParameters)
255    {
256        return allMethodDetails
257            .stream()
258            .filter((ReflHTML<Method> refl) -> refl.entity.numParameters() == numParameters);
259    }
260    
261    /**
262     * Returns a list as a {@code java.util.stream.Stream} of all
263     * Reflected-HTML-{@link Constructor} instances that have the specified number of parameters.
264     * 
265     * @param numParameters The number of parameters contained by the {@link Constructor} being
266     * searched for.
267     * 
268     * @return A Java Stream containing all {@link Constructor}-{@link ReflHTML} instances that
269     * match the provided {@code 'numParameters'} specifier.
270     */
271    public Stream<ReflHTML<Constructor>> findConstructorHTML(int numParameters)
272    {
273        return allConstructorDetails
274            .stream()
275            .filter((ReflHTML<Constructor> refl) -> refl.entity.numParameters() == numParameters);
276    }
277
278    /**
279     * The Reflected-HTML Field having the specified name, or null if no such field exists
280     * 
281     * @param fieldName The name of the field being searched
282     * 
283     * @return The {@code ReflHTML<Field>} instance, from {@code 'this'} Java Doc Page, whose name
284     * matches {@code fieldName}, or null it wasn't found.
285     */
286    public ReflHTML<Field> findFieldHTML(String fieldName)
287    {
288        for (ReflHTML<Field> f : allFieldDetails) if (f.entity.name.equals(fieldName)) return f;
289        return null;
290    }
291
292    /**
293     * The Reflected-HTML Enum-Constant having the specified name, or null if no such constant
294     * exists
295     * 
296     * @param enumConstantName The name of the constant being searched
297     * 
298     * @return The {@code ReflHTML<EnumConstant>} instance, from {@code 'this'} Java Doc Page,
299     * whose name matches {@code enumConstantName}, or null it wasn't found.
300     * 
301     * @throws UpgradeException Only a Java {@link CIET}/Type {@code 'enum'} is allowed to declare
302     * Enum-Constants, and therefore this exception throws <I>when this method is invoked on a
303     * Java Doc HTML File that doesn't represent an {@code enum}.</I>
304     */
305    public ReflHTML<EnumConstant> findECHTML(String enumConstantName)
306    {
307        if (this.ciet != CIET.ENUM) throw new UpgradeException(
308            "Finding Enumeration-Constants is only possible with HTML Files for Java 'enum' " +
309            "Type's.  This file is of type [" + this.ciet.toString() + "]"
310        );
311
312        for (ReflHTML<EnumConstant> ec : allECDetails)
313            if (ec.entity.name.equals(enumConstantName))
314                return ec;
315
316        return null;
317    }
318
319    /**
320     * The Reflected-HTML Annotation-Element having the specified name, or null if no such element
321     * exists
322     * 
323     * @param annotationElemName The name of the constant being searched
324     * 
325     * @return The {@code ReflHTML<EnumConstant>} instance, from {@code 'this'} Java Doc Page,
326     * whose name matches {@code annotationElemName}, or null it wasn't found.
327     * 
328     * @throws UpgradeException Only a Java {@link CIET}/Type {@code '@interface'} is allowed to
329     * declare Annotation-Elements, and therefore this exception throws <I>when this method is
330     * invoked on a Java Doc HTML File that doesn't represent an annotation.</I>
331     */
332    public ReflHTML<AnnotationElem> findAEHTML(String annotationElemName)
333    {
334        if (this.ciet != CIET.ANNOTATION) throw new UpgradeException(
335            "Finding Annotation-Elements is only possible with HTML Files for Java '@interface' " +
336            "(Annotation) Type's.  This file is of type [" + this.ciet.toString() + "]"
337        );
338
339        for (ReflHTML<AnnotationElem> ae : allAEDetails)
340            if (ae.entity.name.equals(annotationElemName))
341                return ae;
342
343        return null;
344    }
345
346
347    // ********************************************************************************************
348    // ********************************************************************************************
349    // Find Refl<HTML> Entities
350    // ********************************************************************************************
351    // ********************************************************************************************
352
353
354    /**
355     * Finds a matching {@link ReflHTML} instance whose internal {@code 'entity'} field has an
356     * ID number that matches input-parameter {@code 'declarationID'}.
357     * 
358     * @param declarationID Whenever any instance of a sub-class of {@link Declaration} is created,
359     * it is given a unique id that uniquely identifies it across the entire life-cycle of the JVM
360     * that is currently running.
361     * 
362     * @param c This must be a Java {@code java.lang.Class} from one of the following:
363     * {@link Constructor}, {@link Method}, {@link Field}, {@link EnumConstant} or
364     * {@link AnnotationElem}.
365     * 
366     * <BR /><BR /><B>NOTE:</B> This class is very easily obtained by simple using the
367     * {@code 'enum'} field {@link Entity#upgraderReflectionClass}.  To pass the appropriate class
368     * for a method, simply pass {@code Entity.METHOD.upgraderReflectionClass} to this parameter.
369     * 
370     * <BR /><BR /><B>ALSO:</B> Even more easy (if you know the member/entity type), you can
371     * hard-code / hand-type the class yourself - for instance {@code Method.class}.  If you were
372     * searching for a {@code ReflHTML<Field>}, you would pass {@code Field.class} to this
373     * parameter.
374     * 
375     * @return The {@link ReflHTML} instance whose HTML describes the Method, Field, or Constructor
376     * etc... whose actual Reflected-class has an ID that matches {@code 'declarationID'}.  Note
377     * that the second parameter {@code 'c'} is primarily used to "speed up" the search process.
378     * 
379     * <DIV CLASS=EXAMPLE>{@code
380     * // Note the 'Method' being passed is Torello.JavaDoc.Method (not java.lang.reflect.Method)
381     * ReflHTML<Method> refl = jdhf.findEntity(someEntityID, Method.class);
382     * }</DIV>
383     * 
384     * @throws IllegalArgumentException If the value passed to {@code 'declarationID'} is negative.
385     */
386    @SuppressWarnings("unchecked") // Seems like the Java-Compiler is failing on this one.
387    public <ENTITY extends Declaration> ReflHTML<ENTITY> findReflHTML
388        (int declarationID, Class<ENTITY> c)
389    {
390        if (declarationID < 0) throw new IllegalArgumentException
391            ("You have passed a negative declarationID: " + declarationID);
392
393        if (Constructor.class.equals(c)) // This is **CLEARLY** not an unchecked cast!
394            for (ReflHTML<Constructor> r : allConstructorDetails)
395                { if (r.entity.id == declarationID) return (ReflHTML<ENTITY>) r; }
396
397        else if (Method.class.equals(c))
398            for (ReflHTML<Method> r : allMethodDetails)
399                { if (r.entity.id == declarationID) return (ReflHTML<ENTITY>) r; }
400
401        else if (Field.class.equals(c))
402            for (ReflHTML<Field> r : allFieldDetails)
403                { if (r.entity.id == declarationID) return (ReflHTML<ENTITY>) r; }
404
405        else if (EnumConstant.class.equals(c))
406            for (ReflHTML<EnumConstant> r : allECDetails)
407                { if (r.entity.id == declarationID) return (ReflHTML<ENTITY>) r; }
408
409        else if (AnnotationElem.class.equals(c))
410            for (ReflHTML<AnnotationElem> r : allAEDetails)
411                { if (r.entity.id == declarationID) return (ReflHTML<ENTITY>) r; }
412
413        return null;
414    }
415
416
417    // ********************************************************************************************
418    // ********************************************************************************************
419    // Constructor and Constructor-Helper
420    // ********************************************************************************************
421    // ********************************************************************************************
422
423
424    // MESSAGER
425    //  1) INVOKES:     assertFailHTML
426    //  2) INVOKED-BY:  MainFilesProcessor *ONLY* (once)
427    //  3) RETURNS:     NOTHING, this is a constructor
428    //  4) THROWS:      JavaDocHTMLParseException (assertFailHTML)
429    //
430    //  NOTE: This makes many calls to the "ReflHTML" constructor, which obeys these 
431    //        Messager Rules as well.  (Expects nothing, only uses assertFailHTML)
432
433    public JavaDocHTMLFile(
434            final UpgradePredicates     predicates,
435            final PathsAndTypes         pathsTypes,
436            final String                jdHTMLFileName,
437            final JavaSourceCodeFile    jscf,
438            final RelativePathStr       dotDots,
439            final JDHFHeaderFacts       jdhfHeaderFacts
440        )
441    {
442        // The 'super' constructor must be on the first line.  This is the signature of that
443        // Constructor.
444        //
445        // protected ParsedFile​(
446        //      String fileName, String name, String packageName, CIET ciet,
447        //      String[] genericParameters, String fullyQualifiedName
448        // )
449
450        super(
451            jdHTMLFileName, // HTML File Name
452            jdhfHeaderFacts.simpleNameWithGenerics, // Un-Qualified-Name, Including GTP's (if any)
453            jdhfHeaderFacts.packageName,            // The Java "Package Name"
454            jdhfHeaderFacts.ciet,                   // CIET, This is the source-code file 'kind'
455            jdhfHeaderFacts.genericParams,          // List of "GTP Names" - if there are any
456            jdhfHeaderFacts.cietFullNameNoGenerics, // Fully Qualified Class Name, Without GTP's
457                                                    // NOT USED: jdhfHeaderFacts.srcCodeFileName
458            jscf.startLineNumber,
459            jscf.endLineNumber,
460            jscf.jdStartLineNumber,
461            jscf.jdEndLineNumber,
462            jscf.typeLineCount,
463            jscf.typeSizeChars,
464            jscf.javaSrcFileAsStr
465        );
466
467
468        // ****************************************************************************************
469        // ****************************************************************************************
470        // BEGINNING INITIALIZATIONS
471        // ****************************************************************************************
472        // ****************************************************************************************
473
474
475        // NOW, THIS IS PRIVATE, IT WASN'T IN THE PAST.
476        // Since breaking up the processing into small pieces (optimization), this MUST BE PRIVATE
477
478        final Vector<HTMLNode> fileVec = this.fileVec = jdhfHeaderFacts.fileVec;
479
480        // The relative-path string to the root javadoc directory (comprised of "../../..")
481        this.dotDots = dotDots;
482
483        // The mirros for @StaticFunctional **AND** JDHeaderBackgroundImg
484        this.annotationsMirror = jscf.annotationsMirror;
485
486
487        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
488        // URL to the corresponding "/src-html/" file (if it exists) - **INCLUDING LINE-NUMBERS**
489        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
490        //
491        // For "inner-classes", there is now a new-and-improved way to link to the JavaDoc source
492        // file.  JavaDoc actually makes a mess out of **INNER-CLASSES** by making a duplicate /
493        // copy of the Java-Source-Code-As-HTML for each-and-every inner-class!  This means that
494        // if there were say... 10 inner classes ... (as in Torello.Browser classes), there are
495        // 10 COPIES OF THE EXACT SAME FILES
496        //
497        // This helps clean that up...  Note that the actual deletion of these duplicate src-file's
498        // is actually done by class "ExtraFilesProcessor" (right at the top of the class)
499        //
500        // NOTE: Perhaps the Java 17 JavaDoc doesn't make this seriously egregious error, but the
501        //       JavaDoc released with JDK 11 seems to be doing that.  I need to start upgrading
502        //       for JDK 17 pretty soon...
503        //
504        // ALSO: Upgrade.getSrcHTMLFile(..) ==> a one-line of code HashMap lookup (no Messager)
505
506        this.srcAsHTMLFileURL = this.isInner
507
508            ? this.dotDots.fileSystem + pathsTypes.srcHTMLFiles.get(
509                this.packageName + '.' +
510                this.simpleName.substring(0, this.simpleName.indexOf('.'))
511            )
512            : this.dotDots.fileSystem + pathsTypes.srcHTMLFiles.get(this.fullyQualifiedName);
513
514        /*
515        if (this.isInner) System.out.println(
516            "srcAsHTMLFile: " + this.srcAsHTMLFileURL +
517            "\n" + this.packageName + '.' +
518            this.simpleName.substring(0, this.simpleName.indexOf('.'))
519        );
520        */
521
522
523        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
524        // Get the Hilited Source File URL.  This should be null if the file isn't being hilited.
525        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
526        //
527        // The class "NavButtons" will use this FileURL.  The class HiLiteSrcCodeFile will actually
528        // do that hiliting.
529
530        if (! predicates.hiLiteSourceCodeFileFilter.test(this.fullyQualifiedName))
531            this.hiLitedSrcFileURL = null;
532
533        else this.hiLitedSrcFileURL =
534
535            "hilite-files/" +
536            (this.isInner
537                ? this.simpleName.substring(0, this.simpleName.indexOf('.'))
538                : this.simpleName) +
539            ".java.html";
540
541
542        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
543        // REMOVE THIS STUFF, **IF REQUESTED**  DO THIS **BEFORE** THE PARSING EVEN STARTS
544        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
545        //
546        // The user has the option of removing an **ENTIRE** details section, on request.  This is
547        // particularly useful for things like an "enum" that has lots of constants where each 
548        // constant detail would be documented ad nauseum.  This also used by the search-classes in
549        // the NodeSearch package where, for example, InnerTagFind has 100 methods, each of which
550        // take some slightly different variant of the exact same parameters.
551        //
552        // NOTE: The user even has the option of removing **ALL** Details (from all
553        // detail-sections)
554        //
555        // BTW: Every time you try to find where there is a test to check the value of
556        //      "methodDetailsRemoved" or "methodDetailsRemoved", remember, these Detail-Removal
557        //      Steps happen BEFORE THIS FILE'S HTML-CONTENT IS EVEN PARSED INTO Refl's !!!
558        //      SO - NO, The class "DetailsProcessor" doesn't check these booleans before
559        //      processing these ReflHTML's, because these Detail/ReflHTML's are never even created
560        //      to begin with - Notice the Details.removeAllDetails happens, right here, right now.
561
562        if (predicates.removeAllDetailsFilter.test(this.fullyQualifiedName))
563        {
564            try
565                { Details.removeAllDetails(fileVec); }
566
567            catch (Exception e)
568                { Messager.assertFailHTML(e, "Unexpected-Exception Removing Details HTML", null); }
569
570            this.methodDetailsRemoved = this.fieldDetailsRemoved = this.constructorDetailsRemoved =
571                this.ecDetailsRemoved = this.aeDetailsRemoved = true;
572        }
573
574        // Same-Story, but this only removes sub-sections of the generalized "Details Sections" on
575        // a Java-Doc Web-Page.  The "Constructor Details" could be removed without removing the
576        // Method-Details at all.
577
578        else try 
579        {
580            UpgradePredicates p = predicates;
581
582            if (this.methodDetailsRemoved =
583                    p.removeAllMethodDetailsFilter.test(this.fullyQualifiedName))
584                Details.removeAllDetails(fileVec, Entity.METHOD);
585
586            if (this.fieldDetailsRemoved =
587                    p.removeAllFieldDetailsFilter.test(this.fullyQualifiedName))
588                Details.removeAllDetails(fileVec, Entity.FIELD);
589
590            if (this.constructorDetailsRemoved =
591                    p.removeAllConstructorDetailsFilter.test(this.fullyQualifiedName))
592                Details.removeAllDetails(fileVec, Entity.CONSTRUCTOR);
593
594            if (this.ecDetailsRemoved =
595                    p.removeAllECDetailsFilter.test(this.fullyQualifiedName))
596                Details.removeAllDetails(fileVec, Entity.ENUM_CONSTANT);
597
598            if (this.aeDetailsRemoved =
599                    p.removeAllAEDetailsFilter.test(this.fullyQualifiedName))
600                Details.removeAllDetails(fileVec, Entity.ANNOTATION_ELEM);
601        }
602
603        catch (Exception e)
604        {
605            Messager.assertFailHTML(e, "Unexpected-Exception Removing Details HTML", null);
606
607            throw new UnreachableError();
608                // Since this is a constructor, "return Messager..."" **CANNOT** work here.\
609                // If this is not here => compiler gives "might not have been initialized" errors
610        }
611
612
613        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
614        // Header-Footer
615        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
616        //
617        // INVOKED-BY: JavaDocHTMLFile *ONLY* (once)
618
619        this.headerFooter = new HeaderFooterHTML(fileVec, this.ciet);
620
621
622        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
623        // Now add the CSS-Tags to the header & footer, do this here...
624        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
625        //
626        // INVOKED-BY: JavaDocHTMLFile Constructor (once)
627
628        if (predicates.cssTagsFilter.test(this.fullyQualifiedName))
629            CSSTagsTopAndSumm.addTagsToDetailBanners(fileVec);
630
631
632        // ****************************************************************************************
633        // ****************************************************************************************
634        // DETAILS ENTRIES
635        // ****************************************************************************************
636        // ****************************************************************************************
637
638
639        HNLIInclusive       iter;
640        Vector<HTMLNode>    details;
641        DotPair             dp;
642
643
644        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
645        // Parse the Java Doc HTML "Method Details", one by one.  Add to internal Vectors.
646        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
647
648        Function<DotPair, ReflHTML<Method>> getMethod = (DotPair methodDetail) ->
649        {
650            // Retrieve the signature of the method from the Java Doc HTML
651            final DotPair signature = TagNodeFindInclusive.first
652                (fileVec, methodDetail.start, methodDetail.end, "pre");
653
654            if (signature == null) Messager.assertFailHTML
655                ("Method Detail Section does not appear to have a Signature <PRE>", null);
656
657            // SignatureParse.parseECSignature: is called twice:
658            //  Once from JavaDocHTMLFile-Constructor: using the Detail-HTML-Signature
659            //  Once from SummaryTableHTML-Constructor: using the Summary-HTML-Signature
660            //
661            // USES: Messager.assertFailHTML() (JavaDocHTMLParseException)
662
663            final Method method = SignatureParse.parseMethodSignature
664                (Util.textNodesString(fileVec, signature), jscf, this);
665
666            // ParsedFile (parent-class) "addMethod" (it's a one-liner, no Messager)
667            addMethod(method);
668
669            return new ReflHTML<>(
670                method, methodDetail, fileVec, Entity.METHOD,
671                getDetailID(fileVec, methodDetail, method),
672                this.isInner ? this.srcAsHTMLFileURL : null
673            );
674        };
675
676        List<DotPair> l = Details.sectionAllDetailsDP(fileVec, Entity.METHOD);
677
678        this.allMethodDetails = new ReadOnlyArrayList<>(l, getMethod, l.size());
679
680
681        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
682        // Parse the Java Doc HTML "Constructor Details", one by one.  Add to internal Vectors.
683        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
684
685        Function<DotPair, ReflHTML<Constructor>> getConstructor = (DotPair constructorDetail) ->
686        {
687            // Retrieve the signature of the constructor from the Java Doc HTM
688            final DotPair signature = TagNodeFindInclusive.first
689                (fileVec, constructorDetail.start, constructorDetail.end, "pre");
690
691            if (signature == null) Messager.assertFailHTML
692                ("Constructor Detail Section does not appear to have a Signature <PRE>", null);
693
694            // SignatureParse.parseConstructorSignature: is called twice:
695            //  Once from JavaDocHTMLFile-Constructor: using the Detail-HTML-Signature
696            //  Once from SummaryTableHTML-Constructor: using the Summary-HTML-Signature
697            //
698            // USES: Messager.assertFailHTML() (JavaDocHTMLParseException)
699
700            final Constructor constructor = SignatureParse.parseConstructorSignature
701                (Util.textNodesString(fileVec, signature), jscf, this);
702
703            // ParsedFile (parent-class) "addConstructor" (it's a one-liner, no Messager)
704            addConstructor(constructor);
705
706            return new ReflHTML<>(
707                constructor, constructorDetail, fileVec, Entity.CONSTRUCTOR,
708                getDetailID(fileVec, constructorDetail, constructor),
709                this.isInner ? this.srcAsHTMLFileURL : null
710            );
711        };
712
713        l = Details.sectionAllDetailsDP(fileVec, Entity.CONSTRUCTOR);
714
715        this.allConstructorDetails = new ReadOnlyArrayList<>(l, getConstructor, l.size());
716
717
718        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
719        // Parse the Java Doc HTML "Field Details", one by one.  Add to internal Vectors.
720        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
721
722        Function<DotPair, ReflHTML<Field>> getField = (DotPair fieldDetail) ->
723        {
724            // Retrieve the signature of the field from the Java Doc HTML
725            final DotPair signature = TagNodeFindInclusive.first
726                (fileVec, fieldDetail.start, fieldDetail.end, "pre");
727
728            if (signature == null) Messager.assertFailHTML
729                ("Field Detail Section does not appear to have a Signature <PRE>", null);
730
731            // SignatureParse.parseFieldSignature: is called twice:
732            //  Once from JavaDocHTMLFile-Constructor: using the Detail-HTML-Signature
733            //  Once from SummaryTableHTML-Constructor: using the Summary-HTML-Signature
734            //
735            // USES: Messager.assertFailHTML() (JavaDocHTMLParseException)
736            //
737            // HERE, pass 'genericParameters' because Java Doc inserts the definition into
738            // the signature on the web-page.  They have to be removed, or JP throws exception.
739
740            final Field field = SignatureParse.parseFieldSignature(
741                Util.textNodesString(fileVec, signature),
742                genericParameters.size() > 0,
743                jscf, this
744            );
745
746            // ParsedFile (parent-class) "addField" (it's a one-liner, no Messager)
747            addField(field);
748
749            return new ReflHTML<>(
750                field, fieldDetail, fileVec, Entity.FIELD,
751                getDetailID(fileVec, fieldDetail, field),
752                this.isInner ? this.srcAsHTMLFileURL : null
753            );
754        };
755
756        l = Details.sectionAllDetailsDP(fileVec, Entity.FIELD);
757
758        this.allFieldDetails = new ReadOnlyArrayList<>(l, getField, l.size());
759
760
761        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
762        // Parse the Java Doc HTML "Enumeration-Constant Details".  Add to the internal Vectors.
763        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
764
765        Function<DotPair, ReflHTML<EnumConstant>> getEC = (DotPair ecDetail) ->
766        {
767            // Retrieve the signature of the enumeration-constant from the Java Doc HTML
768            final DotPair signature = TagNodeFindInclusive.first
769                (fileVec, ecDetail.start, ecDetail.end, "pre");
770
771            if (signature == null) Messager.assertFailHTML
772                ("EC Detail Section does not appear to have a Signature <PRE>", null);
773
774            // SignatureParse.parseECSignature: is called twice:
775            //  Once from JavaDocHTMLFile-Constructor: using the Detail-HTML-Signature
776            //  Once from SummaryTableHTML-Constructor: using the Summary-HTML-Signature
777            //
778            // USES: Messager.assertFailHTML() (JavaDocHTMLParseException)
779
780            final EnumConstant ec = SignatureParse.parseECSignature
781                (Util.textNodesString(fileVec, signature), jscf, this);
782
783            // ParsedFile (parent-class) "addEnumConstant" (it's a one-liner, no Messager)
784            addEnumConstant(ec);
785
786            return new ReflHTML<EnumConstant>(
787                ec, ecDetail, fileVec, Entity.ENUM_CONSTANT,
788                getDetailID(fileVec, ecDetail, ec),
789                this.isInner ? this.srcAsHTMLFileURL : null
790            );
791        };
792
793        l = Details.sectionAllDetailsDP(fileVec, Entity.ENUM_CONSTANT);
794
795        this.allECDetails = new ReadOnlyArrayList<>(l, getEC, l.size());
796
797
798        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
799        // Parse the Java Doc HTML "Annotation-Element Details".  Add to the internal Vectors.
800        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
801
802        Function<DotPair, ReflHTML<AnnotationElem>> getAE = (DotPair aeDetail) ->
803        {
804            // Retrieve the signature of the annotation-element from the Java Doc HTML
805            final DotPair signature = TagNodeFindInclusive.first
806                (fileVec, aeDetail.start, aeDetail.end, "pre");
807
808            if (signature == null) Messager.assertFailHTML
809                ("Detail Section does not appear to have a Signature <PRE>", null);
810
811            // SignatureParse.parseAESignature: is called twice:
812            //  Once from JavaDocHTMLFile-Constructor: using the Detail-HTML-Signature
813            //  Once from SummaryTableHTML-Constructor: using the Summary-HTML-Signature
814            //
815            // USES: Messager.assertFailHTML() (JavaDocHTMLParseException)
816
817            final AnnotationElem ae = SignatureParse.parseAESignature
818                (Util.textNodesString(fileVec, signature), jscf, this);
819
820            // ParsedFile (parent-class) "addAnnotationElem" (it's a one-liner, no Messager)
821            addAnnotationElem(ae);
822
823            return new ReflHTML<AnnotationElem>(
824                ae, aeDetail, fileVec, Entity.ANNOTATION_ELEM,
825                getDetailID(fileVec, aeDetail, ae),
826                this.isInner ? this.srcAsHTMLFileURL : null
827            );
828        };
829
830        l = Details.sectionAllDetailsDP(fileVec, Entity.ANNOTATION_ELEM);
831
832        this.allAEDetails = new ReadOnlyArrayList<>(l, getAE, l.size());
833
834
835        // ****************************************************************************************
836        // ****************************************************************************************
837        // SUMMARIES ENTRIES
838        // ****************************************************************************************
839        // ****************************************************************************************
840
841
842        // if (! Q.YN(C.BGREEN + "Should this continue?" + C.RESET)) System.exit(1);
843
844        RetN r = SummaryTableHTML.parseAllSummaryTables(fileVec, jscf, this);
845
846        this.methodSummaryTable         = r.GET(1);
847        this.fieldSummaryTable          = r.GET(2);
848        this.constructorSummaryTable    = r.GET(3);
849        this.ecSummaryTable             = r.GET(4);
850        this.oaeSummaryTable            = r.GET(5);
851        this.raeSummaryTable            = r.GET(6);
852        this.ntSummaryTable             = r.GET(7);
853
854        @SuppressWarnings("rawtypes")
855        Stream.Builder<SummaryTableHTML> b = Stream.builder();
856        
857        if (methodSummaryTable != null)         b.accept(methodSummaryTable);
858        if (fieldSummaryTable != null)          b.accept(fieldSummaryTable);
859        if (constructorSummaryTable != null)    b.accept(constructorSummaryTable);
860        if (ecSummaryTable != null)             b.accept(ecSummaryTable);
861        if (oaeSummaryTable != null)            b.accept(oaeSummaryTable);
862        if (raeSummaryTable != null)            b.accept(raeSummaryTable);
863        if (ntSummaryTable != null)             b.accept(ntSummaryTable);
864
865        allNonNullSummaryTables = b.build().collect(Collectors.toCollection(Vector::new));
866    }
867
868
869    // ********************************************************************************************
870    // ********************************************************************************************
871    // Retrieve a Detail CSS ID
872    // ********************************************************************************************
873    // ********************************************************************************************
874
875
876    // This just extracts the little HTML ID for the detail-element, This is used by the
877    // NavButton class
878    //
879    // NOTE: The HTML for an Annotation-Element (StaticFunction: "Excuses", "Excused")
880    //       is every-so-slightly different.  The <A ID=..> is AFTER the element
881
882    private static String getDetailID
883        (Vector<HTMLNode> fileVec, DotPair detailLoc, Declaration d)
884    {
885        // Usually this works, except for annotations (look before the top/start of the loc)
886        DotPair anchorLocation = InnerTagFindInclusive.last
887            (fileVec, detailLoc.start - 20, detailLoc.start, "a", "id");
888
889        // If this is an AnnotationElement, ==> Look in ahead, (after the start), rather
890        // than behind, which is what was just done.
891
892        if (anchorLocation == null) if (d instanceof AnnotationElem)
893            anchorLocation = InnerTagFindInclusive.first
894                (fileVec, detailLoc.start, detailLoc.start + 20, "a", "id");
895
896        // Since this error has never happened (except with AnnotationElements), we should
897        // presume that it will never happen, and if it does, an informative error message
898        // is printed.  The Jump-Foward and Jump-Backward Navigation-Buttons help the UI a lot.
899
900        if (anchorLocation == null) Messager.assertFailHTML
901            ("No Anchor with ID Attribute Found for this Detail Element", d.signature);
902
903        /*
904        // Make sure that there is a small Comment with a white-space body in it.  That's the
905        // best effort at checking / making sure this is the right <A ID>...
906        //
907        // NOTE: This has been eliminated, but I'm not exactly sure why.
908
909        CommentNode c       = null;
910        boolean     found   = false;
911
912        for (int i = (anchorLocation.start + 1); i < anchorLocation.end; i++)
913
914            if ((c = fileVec.elementAt(i).ifCommentNode()) != null)
915                if (c.body.trim().length() == 0)
916                    { found=true; break; }
917
918        if (! found) Messager.assertFailHTML
919            ("Anchor with ID does not have <!-- -->", d.signature);
920        */
921
922        // Get the TagNode
923        TagNode tn = (TagNode) fileVec.elementAt(anchorLocation.start);
924
925        // The last sanity check is that the Anchor *DOES NOT* have an HREF=... (which almost
926        // all <A> Anchor Tags usually do).  Except when used for these purposes, they are useless
927        // with an HREF=... Attribute
928        //
929        // If this one has an HREF=... presume it is the wrong one, and complain...
930
931        if (tn.has("href")) Messager.assertFailHTML
932            ("Anchor with ID also has HREF=... Attribute for this Detail Element", d.signature);
933
934        return tn.AV("id");
935    }
936
937
938    // ********************************************************************************************
939    // ********************************************************************************************
940    // Links-Checker Access-Method
941    // ********************************************************************************************
942    // ********************************************************************************************
943
944
945    // StrReplace Helper String[]-Arrays
946    private static final String[] MATCH_STRS    = { "%3C", "%3E", "%5B", "%5D" };
947    private static final String[] REPLACE_STRS  = { "&lt;" , "&gt;", "[", "]" };
948
949    // This Retrieves all CSS-ID's and all <A HREF=...> (the HREF part) from every HTMLNode in
950    // this set, and checks returns them as two TreeSet's.
951    //
952    // Ret2.a: All CSS-ID's found on the page - *NOTE*, this is the *POST-PROCESSED* page
953    // Ret2.b: All HREF Attributes inside of every <A>/Anchor on this page
954    //
955    // This is called by the LinksChecker class
956
957    public /* Made Public With The Big-Move, was Package-Private */
958    Ret2<TreeSet<String>, TreeSet<String>> allIDsAndHREFs()
959    {
960        TreeSet<String> allIDs      = new TreeSet<>();
961        TreeSet<String> allHREFs    = new TreeSet<>();
962        TagNode tn;
963
964        for (HTMLNode n : updatedFileVec)
965
966            if ((tn = n.openTagPWA()) != null)
967            {
968                String id   = tn.AV("id");
969                String href = tn.AV("href");
970
971                if (id != null) allIDs.add(id);
972
973                if (href != null)
974                {
975                    if (href.equals("#top")) continue;
976
977                    if (StrCmpr.startsWithXOR(
978                            href, "http://", "https://", "/",
979                            "javascript:"
980                    ))
981                        continue;
982
983                    allHREFs.add(StrReplace.r(href, MATCH_STRS, REPLACE_STRS));
984                }
985            }
986
987        return new Ret2<>(allIDs, allHREFs);
988    }
989
990
991    // ********************************************************************************************
992    // ********************************************************************************************
993    // simple features exported by this class.
994    // ********************************************************************************************
995    // ********************************************************************************************
996
997
998    // Checks the validity of the HTML on a Java Doc Web-page
999    // @return The Balance Report, generated by class {@link Balance}.  The ;identifies any
1000    // potential unmatched HTML tags.
1001    //
1002    // EXPORT_PORTAL METHOD
1003    // This method is used by Package HTMLProcessors, and doesn't need to be exported to the user.
1004
1005    Hashtable<String, Integer> checkValidity()
1006    {
1007        if (updatedFileVec == null) Messager.assertFailGeneralPurpose
1008            ("For some odd reason, the updatedFileVec has not been set", null);
1009
1010        return Balance.checkNonZero(Balance.check(updatedFileVec));
1011    }
1012
1013    // Saves the Vectorized-HTML back to the file on disk from whence it was loaded.
1014    // @throws IOException This propogates any / all exceptions which might be thrown when
1015    // trying to write the file to the file-system.
1016    //
1017    // EXPORT_PORTAL METHOD
1018    // This method is used by Package HTMLProcessors, and doesn't need to be exported to the user.
1019
1020    void commitFileToDisk() throws java.io.IOException
1021    {
1022        if (updatedFileVec == null) Messager.assertFailGeneralPurpose
1023            ("For some odd reason, the updatedFileVec has not been set", null);
1024
1025        FileRW.writeFile(Util.pageToString(this.updatedFileVec), this.fileName);
1026    }
1027
1028    // Collates and inserts any changes made to the Sub-Sections back into the main page
1029    //
1030    // NO MESSAGER, NO THROWS, THE DATA IS ALL PRIVATE
1031    //
1032    // EXPORT_PORTAL METHOD
1033    // This method is used by Package HTMLProcessors, and doesn't need to be exported to the user.
1034
1035    @SuppressWarnings("unchecked") // The Vector<Replaceable> cast
1036    void commitChanges()
1037    {
1038        final TreeSet<Replaceable> replaceables = new TreeSet<>();
1039
1040        allNonNullSummaryTables.forEach(
1041            (@SuppressWarnings("rawtypes") SummaryTableHTML sTable) ->
1042                replaceables.addAll((Vector<Replaceable>) sTable.allReplaceables())
1043        );
1044
1045        for (ReflHTML<Method> r : allMethodDetails)
1046            replaceables.addAll(r.allReplaceables());
1047
1048        for (ReflHTML<Field> r : allFieldDetails)
1049            replaceables.addAll(r.allReplaceables());
1050
1051        for (ReflHTML<Constructor> r : allConstructorDetails)
1052            replaceables.addAll(r.allReplaceables());
1053
1054        for (ReflHTML<AnnotationElem> r : allAEDetails)
1055            replaceables.addAll(r.allReplaceables());
1056
1057        for (ReflHTML<EnumConstant> r : allECDetails)
1058            replaceables.addAll(r.allReplaceables());
1059
1060        replaceables.addAll(headerFooter.allReplaceables());
1061
1062        this.updatedFileVec = ReplaceNodes.r(fileVec, replaceables, false).a;
1063    }
1064
1065
1066    // ********************************************************************************************
1067    // ********************************************************************************************
1068    // THE NEW-THING: Garbage-Collector Helper?
1069    // ********************************************************************************************
1070    // ********************************************************************************************
1071    //
1072    // Does this help?  Is this "good" for the Garbage-Collect?  Is this going to speed it up,
1073    // or slow it down?  This is just a "C-Styled" FREE or DESTORY method...
1074    // It isn't publicly visible anyway...
1075
1076    void clear()
1077    {
1078        headerFooter.clear();
1079
1080        // private final Vector<SummaryTableHTML> allNonNullSummaryTables;
1081        for (@SuppressWarnings("rawtypes") SummaryTableHTML st : allNonNullSummaryTables)
1082            st.clear();
1083    }
1084}