001package Torello.HTML.Tools.JavaDoc;
002
003import Torello.HTML.*;
004import Torello.HTML.NodeSearch.*;
005
006import Torello.Java.Additional.EffectivelyFinal;
007
008import java.util.*;
009import java.util.stream.*;
010
011/**
012 * <B STYLE='color:darkred;'>Process Java Doc Web-Page:</B>
013 * 
014 * Add several buttons to the Navigation Menu, along with a Detail-Element drop-down menu.
015 * 
016 * <EMBED CLASS="external-html" DATA-FILE-ID=PKG_PRIVATE_MSG>
017 * <EMBED CLASS="external-html" DATA-FILE-ID=NAV_BUTTONS>
018 */
019@StaticFunctional
020public class NavButtons
021{
022    private NavButtons() { }
023
024    private static final TextNode NL = new TextNode("\n");
025
026    private static final String MEMBERS_BUTTON_START =
027        "<LI>&nbsp;|&nbsp;</LI>\n" +
028        "<LI CLASS=DetailsPopupButton onmouseover=" +
029            "'document.getElementById(\"PopUpDIV\").style.display=\"block\";'>" +
030            "<SPAN STYLE='color: #4D7A97;'>MENU</SPAN>\n" +
031
032        // NOTE: The "<NOSCRIPT>" thing actually looks very respectable.  You have to actually
033        //       deactivate JavaScript in Chrome to see this popup.  To do that, Open up 
034        //       "Chrome Dev Tools" and Press "Control-Shift P" (on Windows), then start typing
035        //       the word "JavaScript" into the Run-Search-Bar that pops up.  It will display 
036        //       a button that allows to disable JavaScript for the window you are on
037
038        "<NOSCRIPT>\n" +
039        "<DIV CLASS=NoScriptDetailsPopup>JavaScript is disabled on your browser.</DIV>\n" +
040        "</NOSCRIPT>\n" +
041
042        // The Pop-Up <DIV> is just an "undisplayable" <DIV> inside the <LI>.  It cannot be
043        // displayed unless the CONTAINING/SURROUNDING <LI> gets a "MouseOver" event.
044        //
045        // NOTE: That the actual hiding of this PopUp Menu is done right here.  Whenever this
046        //       <DIV> gets a "MouseClick" or a "MouseOut" event, it hides this DIV again, by
047        //       setting it's CSS-'display' property back to "none"
048
049        "<DIV ID=PopUpDIV CLASS=DetailsPopup onclick='this.style.display=\"none\"' " +
050            "onmouseout='this.style.display=\"none\"'>\n" +
051        "<TABLE>\n";
052
053    private static final String MEMBERS_BUTTON_END = "\n</TABLE>\n</DIV>\n</LI>\n";
054
055
056    // NOTE: The "unchecked" eventually became necessary because r.html was somehow converted
057    //       into a "rawtype" as well, and that cause
058
059    //@SuppressWarnings({"rawtypes", "unchecked"})
060    static boolean addButtonsToTop(JavaDocHTMLFile jdhf)
061    {
062        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
063        // Build the Top NavBar Buttons: "TOP", "SRC", "HILITED"
064        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
065
066        int LN = (jdhf.jdStartLineNumber != -1)
067            ? jdhf.jdStartLineNumber
068            : jdhf.startLineNumber;
069
070        String firstLinksMenuStr =
071            "<UL CLASS=subNavList>\n" +
072            "\t<LI>PAGE:&nbsp;</LI>\n" +
073            "\t<LI><A HREF='#top'>TOP</A></LI>\n" +
074            ((jdhf.srcAsHTMLFileURL != null)
075                ? ("\t<LI>&nbsp;|&nbsp;</LI>\n" +
076                    "\t<LI><A HREF='" + jdhf.srcAsHTMLFileURL +
077                    (jdhf.isInner ? ("#line." + LN) : "") +
078                    "'>SRC</A></LI>\n")
079                : "") +
080            ((jdhf.hiLitedSrcFileURL != null)
081                ? ("\t<LI>&nbsp;|&nbsp;</LI>\n" +
082                    "<LI><A HREF='" + jdhf.hiLitedSrcFileURL +
083                    (jdhf.isInner ? ("#L" + LN) : "") + "'>HILITED" +
084                    "</A></LI>\n")
085                : "");
086
087
088        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
089        // Build the Nav-Bar "Member's List" Drop-Down Menu
090        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
091
092        // The output HTML is stored here
093        StringBuilder               sb      = new StringBuilder();
094        EffectivelyFinal<Boolean>   first   = new EffectivelyFinal<>(true);
095
096        // *** *** NOTE *** ***
097        // Annotation-Elements & Enum-Constants are FIRST
098        // THEY SHOULD BE LISTED FIRST IN THE MENU IS **WHY** ==> They are "special"
099
100
101        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
102        // Annotation Elements
103        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
104
105        first.f = true;
106        if (jdhf.ciet == CIET.ANNOTATION) jdhf  // (ReflHTML<AnnotationElem> r) ->
107            .allAEDetails()
108            .filter(r -> r.htmlID != null)
109            .sorted((r1, r2) -> r1.entity.compareTo(r2.entity))
110            .forEachOrdered(r ->
111            {
112                sb.append(
113                    (first.f
114                        ? ("\t<TR CLASS=DPL><TH COLSPAN=2><DIV>Annotation Elements" +
115                            "</DIV></TH></TR>\n")
116                        : "") +
117                    "\t<TR CLASS=DPI onclick='document.location=\"#" + r.htmlID + "\";'>\n" +
118                    "\t\t<TD>" + r.entity.typeJOW + "</TD>\n" +
119                    "\t\t<TD><SPAN>" + r.entity.name + " &nbsp; </SPAN></TD>\n" +
120                    "\t</TR>\n"
121                );
122
123                first.f = false;
124            });
125
126
127        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
128        // Enum Constants
129        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
130
131        first.f = true;
132        if (jdhf.ciet == CIET.ENUM) jdhf  // (ReflHTML<EnumConstant> r) ->
133            .allECDetails()
134            .filter(r -> r.htmlID != null)
135            .sorted((r1, r2) -> r1.entity.compareTo(r2.entity))
136            .forEachOrdered(r ->
137            {
138                sb.append(
139                    (first.f
140                        ? "\t<TR CLASS=DPL><TH COLSPAN=2><DIV>Enum Constants</DIV></TH></TR>\n"
141                        : "") +
142                    "\t<TR CLASS=DPI onclick='document.location=\"#" + r.htmlID + "\";'>\n" +
143                        "\t\t<TD COLSPAN=2><SPAN>" + r.entity.name + "</SPAN> &nbsp; </TD>\n" +
144                    "\t</TR>\n"
145                );
146
147                first.f = false;
148            });
149
150
151        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
152        // Fields
153        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
154
155        first.f = true;
156        jdhf.allFieldDetails() // (ReflHTML<Field> r) ->
157            .filter(r -> r.htmlID != null)
158            .sorted((r1, r2) -> r1.entity.compareTo(r2.entity))
159            .forEachOrdered(r ->
160            {
161                sb.append(
162                    (first.f
163                        ? "\t<TR CLASS=DPL><TH COLSPAN=2><DIV>Fields</DIV></TH></TR>\n"
164                        : "") +
165                    "\t<TR CLASS=DPI onclick='document.location=\"#" + r.htmlID + "\";'>\n" +
166                    "\t\t<TD>" + r.entity.typeJOW + "</TD>\n" +
167                    "\t\t<TD><SPAN>" + r.entity.name + "</SPAN> &nbsp; </TD>\n" +
168                    "\t</TR>\n"
169                );
170
171                first.f = false;
172            });
173
174
175        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
176        // Constructors
177        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
178
179        first.f = true;
180        jdhf.allConstructorDetails() // (ReflHTML<Constructor> r) ->
181            .filter(r -> r.htmlID != null)
182            .sorted((r1, r2) -> r1.entity.compareTo(r2.entity))
183            .forEachOrdered(r ->
184            {
185                Constructor c = r.entity;
186                int         n = c.numParameters();
187
188                sb.append(
189                    (first.f
190                        ? "\t<TR CLASS=DPL><TH COLSPAN=2><DIV>Constructors</DIV></TH></TR>\n"
191                        : "") +
192                    "\t<TR CLASS=DPI onclick='document.location=\"#" + r.htmlID + "\";'>\n" +
193                        "\t\t<TD COLSPAN=2><SPAN>" +
194                        c.name + "</SPAN>("
195                );
196
197                first.f = false;
198
199                // Constructors have parameters, and those need to be printed to the output
200                for (int i=1; i <= n; i++) sb.append(
201                    c.getParameterTypeJOW(i) + "&nbsp;" + c.getParameterName(i) + 
202                    ((i < n) ? ", " : "")
203                );
204
205                sb.append(") &nbsp; </TD>\n\t</TR>\n");
206            });
207
208
209        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
210        // Methods
211        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
212
213        first.f = true;
214        jdhf.allMethodDetails()  // (ReflHTML<Method> r) ->
215            .filter(r -> r.htmlID != null)
216            .sorted((r1, r2) -> r1.entity.compareTo(r2.entity))
217            .forEachOrdered(r ->
218            {
219                Method  m = r.entity;
220                int     n = m.numParameters();
221
222                sb.append(
223                    (first.f
224                        ? "\t<TR CLASS=DPL><TH COLSPAN=2><DIV>Methods</DIV></TH></TR>\n"
225                        : "") +
226                    "\t<TR CLASS=DPI onclick='document.location=\"#" + r.htmlID + "\";'>\n" +
227                    "\t\t<TD>" + m.returnTypeJOW + "</TD>\n" +
228                    "\t\t<TD><SPAN>" + m.name + "</SPAN>("
229                );
230
231                first.f = false;
232
233                // Methods have parameters, and those need to be printed to the output
234                for (int i=1; i <= n; i++) sb.append(
235                    m.getParameterTypeJOW(i) + "&nbsp;" + m.getParameterName(i) + 
236                    ((i < n) ? ", " : "")
237                );
238
239                sb.append(") &nbsp; </TD>\n\t</TR>\n");
240            });
241
242
243        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
244        // Close off the Menus, and Finish the StringBuilder
245        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
246
247        // There are classes whose Details are completely removed.  If they were, they certainly
248        // don't need the opening & closing Menu <LI>'s and <DIV>'s
249
250        if (sb.length() > 0)
251        {
252            sb.insert(0, MEMBERS_BUTTON_START); // Opening DetailsMenuPopup 
253            sb.append(MEMBERS_BUTTON_END);      // Closing detailsMenuPopup
254        }
255
256        // Now insert the Initial-Links at the beginning of the StringBuilder.  This is only
257        // done in the last step because the sb.length() is checked to see if there even was a
258        // "Details Members" Menu built in the first place.  It isn't "costly" to do an insert
259        // on a StringBuilder, that's kind of the whole point of the class.
260
261        sb.insert(0, firstLinksMenuStr);
262        sb.append("</UL>\n");
263
264        // Now that everything is built, insert the items into the Java Doc Page.
265        Vector<HTMLNode> topNavBar = jdhf.headerFooter.topNavBar();
266
267        // Debugging Println
268        // System.out.println(Util.pageToString(topNavBar)); Torello.Java.Q.BP();
269
270        // INSERT THIS INTO THE SECOND <UL CLASS=subNavList> on the page
271        int insertLocation = InnerTagFindInclusive.nth
272            (topNavBar, 2, "ul", "class", TextComparitor.C, "subNavList").end + 1;
273
274
275        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
276        // Leave this here for a remembrance...  It's balanced, and this saves time.
277        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
278        //
279        // NORMAL VERSION:
280        // pageTop.addAll(insertLocation, HTMLPage.getPageTokens(sb.toString(), false));
281
282        // CHEATING VERSION:
283        topNavBar.insertElementAt(new TextNode(sb.toString()), insertLocation);
284
285
286        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
287        // Now do the the links
288        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
289        //
290        // *NOTE* Order here *DOES NOT* matter - as long as it is the same in **BOTH** the "links"
291        // retrieval / String-Array builder **AND** in the method that inserts the links
292
293        Stream.Builder<String> b = Stream.builder();
294
295        if (jdhf.ciet == CIET.ANNOTATION)
296            jdhf.allAEDetails().forEachOrdered(ae -> b.accept(ae.htmlID));
297
298        if (jdhf.ciet == CIET.ENUM)
299            jdhf.allECDetails().forEachOrdered(ec -> b.accept(ec.htmlID));
300
301        jdhf.allFieldDetails()          .forEachOrdered(f -> b.accept(f.htmlID));
302        jdhf.allConstructorDetails()    .forEachOrdered(c -> b.accept(c.htmlID));
303        jdhf.allMethodDetails()         .forEachOrdered(m -> b.accept(m.htmlID));
304
305        final String[] links = b.build().toArray(String[]::new);
306
307        addButtonsToDetails(jdhf, links);
308
309        return true;
310    }
311
312    static boolean addButtonsToDetails
313        (JavaDocHTMLFile jdhf, String[] links)
314    {
315        int divID = 0;
316
317        if (jdhf.ciet == CIET.ANNOTATION)
318        {
319            Iterator<ReflHTML<AnnotationElem>> iterAE = jdhf.aeDetailsIterator();
320            while (iterAE.hasNext()) insertNavBar(jdhf, iterAE.next(), links, divID++);
321        }
322
323        if (jdhf.ciet == CIET.ENUM)
324        {
325            Iterator<ReflHTML<EnumConstant>> iterEC = jdhf.ecDetailsIterator();
326            while (iterEC.hasNext()) insertNavBar(jdhf, iterEC.next(), links, divID++);
327        }
328
329        Iterator<ReflHTML<Field>> iterF = jdhf.fieldDetailsIterator();
330        while (iterF.hasNext()) insertNavBar(jdhf, iterF.next(), links, divID++);
331
332        Iterator<ReflHTML<Constructor>> iterC = jdhf.constructorDetailsIterator();
333        while (iterC.hasNext()) insertNavBar(jdhf, iterC.next(), links, divID++);
334
335        Iterator<ReflHTML<Method>> iterM = jdhf.methodDetailsIterator();
336        while (iterM.hasNext()) insertNavBar(jdhf, iterM.next(), links, divID++);
337
338        return true;
339    }
340
341    static void insertNavBar
342        (JavaDocHTMLFile jdhf, ReflHTML<? extends Declaration> r, String[] links, int divID)
343    {
344        if (links.length == 0) return;
345
346        TextNode    DIV             = null;
347        String      srcLink         = null;
348        boolean     srcWasHiLited   = jdhf.hiLitedSrcFileURL != null;
349
350        int lineNum = (r.entity.jdStartLineNumber != -1)
351            ? r.entity.jdStartLineNumber
352            : r.entity.signatureLineNumber;
353
354        // REMEBER: For "Auto-Generated" constructors, and for "Synthetic Methods" (also auto
355        //          generated), there is no source-code for the constructor/method.  In these cases
356        //          class Declaration assigns -1 to the line number.
357
358        if (lineNum == -1) srcWasHiLited = false;
359
360        if (srcWasHiLited) srcLink =
361            "<A HREF='" + jdhf.hiLitedSrcFileURL + "#L" + lineNum + "'>" +
362            "&#11179;</A>";
363
364
365        // If there is *ONLY 1* Detail on the entire page, there is no need to add any of the
366        // arrow navigation buttons at all.  Just add the Source-Code Link, and the arrow to
367        // the Summary-Table <TR>  (the "double-up-arrow")
368
369        if ((links.length == 1) && srcWasHiLited) DIV = new TextNode(
370            "\n<DIV CLASS=ANAV>\n\t" + 
371            "<A HREF='#" + r.entityAsEnum.abbrev + r.entity.id +
372                "'>&#8648;</A>\n\t&nbsp;" + // Double-Arrow Up ⇈
373            (srcWasHiLited ? srcLink : "") +
374            "\n</DIV>\n"
375        );
376
377        // This is TRUE when this is the *FIRST DETAIL* on the page.  It cannot have an
378        // "Up Arrow", just a "Down Arrow' and a Source-Code Link
379
380        else if (divID == 0) DIV = new TextNode(
381            "\n<DIV CLASS=ANAV>\n\t" +
382            "<A HREF='#" + links[1] + "'>&#129095;</A>\n\t&nbsp;" + // Down 🡇
383            "<A HREF='#" + r.entityAsEnum.abbrev + r.entity.id +
384                "'>&#8648;</A>\n\t&nbsp;" + // Double-Arrow Up ⇈
385            (srcWasHiLited ? srcLink : "") +
386            "\n</DIV>\n"
387        );
388
389        // This is TRUE when this is the *LAST DETAIL* on the page.  It cannot have a
390        // "Down Arrow", just an "Up Arrow' and a Source-Code Link
391
392        else if (divID == (links.length - 1)) DIV = new TextNode(
393            "\n<DIV CLASS=ANAV>\n\t" + 
394            "<A HREF='#" + links[links.length - 2] + "'>&#129093;</A>\n\t&nbsp;" + // Up 🡅
395            "<A HREF='#" + r.entityAsEnum.abbrev + r.entity.id +
396                "'>&#8648;</A>\n\t&nbsp;" + // Double-Arrow Up ⇈
397            (srcWasHiLited ? srcLink : "") +
398            "\n</DIV>\n"
399        );
400
401        // Up Arrow, Down Arrow, and Src-Link
402        else DIV = new TextNode(
403            "\n<DIV CLASS=ANAV>\n\t" +
404            "<A HREF='#" + links[divID - 1] + "'>&#129093;</A>\n\t&nbsp;" + // Up 🡅
405            "<A HREF='#" + links[divID + 1] + "'>&#129095;</A>\n\t&nbsp;" + // Down 🡇
406            "<A HREF='#" + r.entityAsEnum.abbrev + r.entity.id +
407                "'>&#8648;</A>\n\t&nbsp;" + // Double-Arrow Up ⇈
408            (srcWasHiLited ? srcLink : "") +
409            "\n</DIV>\n"
410        );
411
412        // Add into the "Name" vector, immediately afer the <H4> .. it is fine...
413        // trust me, i'm a professional
414        if (DIV != null) r.name().add(DIV);
415    }
416}