001package Torello.HTML.Tools.JavaDoc;
002
003import Torello.HTML.*;
004import Torello.HTML.NodeSearch.*;
005
006import Torello.Java.Additional.Ret2;
007import Torello.Java.StorageWriter;
008import Torello.Java.StringParse;
009import Torello.Java.Shell.C;
010
011import java.util.*;
012import java.util.stream.*;
013import java.util.regex.*;
014import java.util.function.Predicate;
015
016/**
017 * <B STYLE='color:darkred;'>Process Java Doc Web-Page:</B>
018 * 
019 * Remove the auto-generated summaries for each Method, Field, Constructor, Enum-Constant, and
020 * Annotation-Element in the Summary Section.
021 * 
022 * <EMBED CLASS="external-html" DATA-FILE-ID=PKG_PRIVATE_MSG>
023 * <EMBED CLASS="external-html" DATA-FILE-ID=CLEAN_SUMM>
024 */
025@StaticFunctional
026public class CleanSummaries
027{
028    private CleanSummaries() { }
029
030    @SuppressWarnings({"unchecked", "rawtypes"})
031    static int removeAllDescriptionsFromSummaries(Iterator<SummaryTableHTML> summaryTables)
032    {
033        Messager.ifVPrintln
034            ("SummaryDescriptions.removeAllDescriptionsFromSummaries(...) ");
035
036        int remCount = 0;
037
038        while (summaryTables.hasNext())
039        {
040            SummaryTableHTML table = summaryTables.next();
041
042            int LAST_COL = (
043                   (table.tableType == Entity.ENUM_CONSTANT)
044                || (table.tableType == Entity.CONSTRUCTOR)
045            )
046                ? 2     // Enum-Constants only have 2 rows: name and description
047                : 3;    // Everything else: type/modifiers, signature, description
048
049            // REMEMBER: Some SummaryTableHTML instances are for "Inherited Entity" *ONLY*
050            //           tables.  If there are no methods/fields/constructors defined inside of
051            //           a type, then there will (obviously) be no <TABLE> ... </TABLE> with
052            //           the method/field/constructor summary-rows.  In such cases, the 'headerRow'
053            //           will be null.
054
055            if (table.headerRow != null)
056                remCount += TagNodeRemoveInclusive.nth(table.headerRow, LAST_COL, "td", "th");
057
058            Iterator<Vector<HTMLNode>> rowIter = table.tableRowIterator();
059
060            while (rowIter.hasNext())
061                remCount += TagNodeRemoveInclusive.nth(rowIter.next(), LAST_COL, "td", "th");
062        }
063
064        if (Messager.isVerbose()) Messager.println(
065            "\tRemoved  " + C.BBLUE + StringParse.zeroPad(remCount, 5) + C.RESET + 
066            " Summary Descriptions HTMLNode's"
067        );
068
069        return remCount;
070    }
071
072    @SuppressWarnings({"unchecked", "rawtypes"})
073    static int typesRemovePackageName(Iterator<SummaryTableHTML> summaryTablesIterator)
074    {
075        int replaceCount = 0;
076
077        while (summaryTablesIterator.hasNext())
078        {
079            SummaryTableHTML summaryTable = summaryTablesIterator.next();
080
081            if (summaryTable.tableType == Entity.ENUM_CONSTANT) continue;
082            if (summaryTable.tableType == Entity.INNER_CLASS)   continue;
083
084            TextNode txn;
085
086            Iterator<Vector<HTMLNode>> rowIterator = summaryTable.tableRowIterator();
087
088            while (rowIterator.hasNext())
089            {
090                Vector<HTMLNode> row = rowIterator.next();
091
092                for (int i=0; i < row.size(); i++)
093
094                    if ((txn = row.elementAt(i).ifTextNode()) != null)
095                    {
096                        String oldStr = txn.str;
097                        String newStr = removePackageNames(oldStr);
098
099                        if (newStr.length() != oldStr.length())
100                        {
101                            row.setElementAt(new TextNode(newStr), i);
102                            replaceCount++;
103                        }
104                    }
105            }
106        }
107
108        return replaceCount;
109    }
110
111
112    // ********************************************************************************************
113    // ********************************************************************************************
114    // Efficient-Replace Type-Package-Name
115    // ********************************************************************************************
116    // ********************************************************************************************
117
118
119    private static final String[] removeStrs =
120    {
121        /* 00 */ "java.util.regex.",
122        /* 01 */ "java.util.stream.",
123        /* 02 */ "java.util.function.",
124        /* 03 */ "java.util.concurrent.",
125        /* 04 */ "java.util.",
126        /* 05 */ "java.lang.reflect.",
127        /* 06 */ "java.lang.", 
128        /* 07 */ "java.net.",
129        /* 08 */ "java.io.", 
130        /* 09 */ "java.math.",
131
132        /* 10 */ "com.github.javaparser.ast.body.",
133        /* 11 */ "com.github.javaparser.ast.",
134    };
135
136    private static final int REM_STRS_1_START   = 0;
137    private static final int REM_STRS_1_END     = 9;    // Loop-Conditional, Uses '<='
138    private static final int REM_STRS_2_START   = 10;
139    private static final int REM_STRS_2_END     = 11;   // Loop-Conditional, Uses '<='
140
141
142    private static final String[] removeStrs2 =
143    {
144    };
145
146    // This one day needs to be entered & included into "class Upgrade"
147    private static void addAnotherRemoveStrs(String[] removeStrs, Predicate<String> quickTest)
148    {
149        for (int i=0; i < removeStrs.length; i++)
150        
151            if (! P1.test(removeStrs[i])) throw new IllegalArgumentException(
152                "The " + i + StringParse.ordinalIndicator(i) + " of this array is not a valid " +
153                "Package String."
154            );
155
156        // CleanSummaries.removeStrs = removeStrs;
157    }
158
159    private static final Predicate<String> P1 =
160        Pattern.compile("^\\w[\\w\\d&]*\\.(\\w[\\w\\d&]*\\.)*$").asPredicate();
161
162    static String removePackageNames(String s)
163    {
164        // Java Stream's shall keep records of where the matches occurred
165        IntStream.Builder   where   = IntStream.builder();
166        IntStream.Builder   which   = IntStream.builder();
167        int                 delta   = 0;
168        final int           END     = s.length() - 10; // ("java.io.XX".length())
169        String              TEMP    = null;
170
171        // This part of the code finds the locations of all the matches in the input string.
172        // It does not build the new String, but rather, finds indexes first.  This way a
173        // char[] array can be built, and then populated with the updated sub-strings.
174
175        TOP:
176        for (int i=0; i < END; i++)
177
178            if  (   (s.charAt(i)    == 'j')
179                &&  (s.charAt(i+1)  == 'a')
180                &&  (s.charAt(i+2)  == 'v')
181                &&  (s.charAt(i+3)  == 'a')
182                &&  (s.charAt(i+4)  == '.')
183            )
184            {
185                for (int j=REM_STRS_1_START; j <= REM_STRS_1_END; j++)
186
187                    if (s.regionMatches(i, TEMP = removeStrs[j], 0, TEMP.length()))
188                    {
189                        where.accept(i);        // WHERE a match has occured
190                        which.accept(j);        // WHICH match has occured
191                        delta -= TEMP.length(); // num-characters Size-Reduction
192                        i += TEMP.length() - 1; // Advance the index pointer
193
194                        continue TOP;
195                    }
196            }
197
198            else if (   (s.charAt(i)    == 'c')
199                    &&  (s.charAt(i+1)  == 'o')
200                    &&  (s.charAt(i+2)  == 'm')
201                    &&  (s.charAt(i+3)  == '.')
202                    &&  (s.charAt(i+4)  == 'g')
203            )
204                for (int j=REM_STRS_2_START; j <= REM_STRS_2_END; j++)
205                {
206                    if (s.regionMatches(i, TEMP = removeStrs[j], 0, TEMP.length()))
207                    {
208                        where.accept(i);        // WHERE a match has occured
209                        which.accept(j);        // WHICH match has occured
210                        delta -= TEMP.length(); // num-characters Size-Reduction
211                        i += TEMP.length() - 1; // Advance the index pointer
212
213                        continue TOP;
214                    }
215                }
216
217        // List of indices into the input-String for WHERE matches occurred.
218        int[] wherePosArr = where.build().toArray();
219
220        // List of indices into the match-array for WHICH matches occurred.
221        int[] whichStrIndices = which.build().toArray();
222
223        // The new "Char Array" which will be built into a String.  The "change in size" was
224        // computed earlier
225
226        char[] cArr = new char[s.length() + delta];
227
228        // These are some loop-control variables
229        int     oldStrPos   = 0;
230        int     newStrPos   = 0;
231        int     index       = 0;
232
233        // This is a "Pre-Loop Priming Update" or "Priming Read".  It just
234        // copies the first non-matching sub-string portion to the cArr[]
235
236        int end = (index < whichStrIndices.length) ? wherePosArr[index] : s.length();
237
238        while (oldStrPos != end) cArr[newStrPos++] = s.charAt(oldStrPos++);
239
240        while (index < whichStrIndices.length)
241        {
242            oldStrPos += removeStrs[whichStrIndices[index]].length();
243            index++;
244
245            // Copy the next non-matching sub-string section from the "Old Input String"
246            end = (index < whichStrIndices.length) ? wherePosArr[index] : s.length();
247
248            s.getChars(oldStrPos, end, cArr, newStrPos);
249
250            // Advance the Pointer
251            newStrPos += (end - oldStrPos);
252            oldStrPos = end;
253        }
254
255        return new String(cArr);
256    }
257
258
259    // ********************************************************************************************
260    // ********************************************************************************************
261    // NOTES
262    // ********************************************************************************************
263    // ********************************************************************************************
264
265
266    // One-Day, Soon, There is going to be an Upgrade Class called "JavaDocConfiguration" and
267    // it will allow a user to set which version of JavaDoc (and which Java, possibly) he is
268    // using.  When that happens, these notes are going to b valuable.
269
270    static int removeAll(SummaryTableHTML<?> table)
271    {
272        throw new Torello.Java.UnreachableError();
273            // This method is no longer used, it is being kept around because the notes in
274            // the comments explain some things that will be relevant again, soon.
275
276        // NEWER JavaDoc's add a "Description" column to constructors.  Older Javadoc have a
277        // single column called "Constructor & Description"  The 'if statement' after this 
278        // checks for '3 columns' but constructors only have 2 columns (unlike the others)
279
280        /*
281        DotPair constructorTH = InnerTagFindInclusive.first
282            (fileVec, dp.start, dp.end, "th", "class", TextComparitor.C, "colLast");
283        
284
285        if (constructorTH != null)
286            if (TextNodeFind.first
287                (fileVec, constructorTH.start, constructorTH.end, s -> s.equals("Description")) != -1)
288                    Util.removeRange(fileVec, constructorTH);
289        */
290
291        // NEWER JavaDoc's have a "colSecond" (3 columns)
292        /*
293        if (InnerTagCount.all
294            (fileVec, dp.start, dp.end, "th", "class", TextComparitor.C, "colSecond") > 0)
295        {
296            // This removes the column HEADERS...  It will not be included in the "remove count" 
297            // return value.
298            InnerTagRemoveInclusive.all
299                (fileVec, dp.start, dp.end, "th", "class", TextComparitor.C, "colLast");
300
301            // These are the actual summary-description columns.  Remove them all at the same time.
302            // Return as "remove count"
303            return InnerTagRemoveInclusive.all
304                (fileVec, dp.start, dp.end, "td", "class", TextComparitor.C, "colLast");
305        }
306        */
307
308        /*
309        for (Vector<HTMLNode> row : table.tableRows)
310        {
311            remCount++;
312            TagNodeRemoveInclusive.nth(row, 3, "td");
313        }
314        */
315
316        /*
317        // OLDER JavaDoc's have "colFirst" and "colLast" (2 columns)
318        int             remCount    = 0;
319        HNLIInclusive   iter        = funcPtr.apply(fileVec);
320
321        while (iter.hasNext())
322        {
323            Vector<HTMLNode>    summary = iter.next();
324            int[]               posArr  = TagNodeFind.all(summary, TC.Both, "div");
325
326            // A summary that had html dividers means a "summary description" was present.
327            // The purpose of this method is to remove those.
328            if (posArr.length > 0)
329            {
330                remCount++; 
331                Util.removeRange(summary, posArr[0], posArr[posArr.length - 1] + 1);
332                iter.set(summary);
333            }
334        }
335
336        return remCount;
337        */
338    }
339}