1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
package Torello.HTML;

import Torello.Java.NException;

import java.util.*;

import java.util.stream.IntStream;

public class DPUtil
{
    // ********************************************************************************************
    // ********************************************************************************************
    // To Vector & Sublist
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * This method converts a sublist, represented by a "dotted pair", and converts it into a
     * {@code Vector} of {@code HTMLNode}.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>Retrieval Heuristic:</B>
     * 
     * <BR />It should be obvious that the parameter @code 'dp'} contains fields named
     * {@link DotPair#start} and {@link DotPair#end}.  These two simply represent the starting and
     * ending indices into an HTML page {@code Vector}.  In this method, the intention is that they
     * are indices into the HTML-{@code Vector} parameter simply-named {@code 'html'}.
     * 
     * <BR /><BR />This method cycles through that {@code Vector}, beginning with the field
     * {@code dp.start} (inclusive) and ending with {@code dp.end} (inclusive, as well).  Each
     * {@code HTMLNode} reference within this sublist is inserted into the {@code Vector} that is 
     * ultimately returned.
     * 
     * @param html Any Vectorized-HTML Web-Page, or sub-page
     * 
     * @param dp Any sublist within that HTML page.
     * 
     * @return A {@code Vector} version of the original sublist that was represented by 
     * passed parameter {@code 'dp'}
     */
    public static Vector<HTMLNode> toVector(Vector<? extends HTMLNode> html, DotPair dp)
    {
        Vector<HTMLNode> ret = new Vector<>();

        // NOTE: Cannot return the result of "subList" because it is linked/mapped to the original
        //       Vector.  If changes are made to "subList", those changes will be reflected in the
        //       original HTML Vector.

        ret.addAll(html.subList(dp.start, dp.end + 1));

        return ret;
    }

    /**
     * This will cycle through a "list of sublists" and call the method
     * {@code toVector(Vector<? extends HTMLNode> html, DotPair dp)}
     * on each sublist in the input parameter {@code 'sublists'}  Those sublists will be collected
     * into another {@code Vector} and returned.
     * 
     * @param html Any Vectorized-HTML Web-Page, or sub-page
     * 
     * @param sublists A "List of sublists" within that HTML page.
     * 
     * @return This method shall return a {@code Vector} containing vectors as sublists.
     */
    public static Vector<Vector<HTMLNode>> toVectors
        (Vector<? extends HTMLNode> html, Iterable<DotPair> sublists)
    {
        Vector<Vector<HTMLNode>> ret = new Vector<>();

        for (DotPair sublist : sublists) ret.addElement(toVector(html, sublist));

        return ret;
    }

    /**
     * This will cycle through a "list of sublists" and call the method
     * {@code toVector(Vector<? extends HTMLNode> html, DotPair dp) }
     * on each sublist in the input parameter {@code 'sublists'}.  Those sublists will be
     * collected into another {@code Vector} and returned.
     * 
     * @param html Any Vectorized-HTML Web-Page, or sub-page
     * 
     * @param sublists A "List of sublists" within that HTML page.
     * 
     * @return This method shall return a {@code Vector} containing vectors as sublists.
     */
    public static Vector<SubSection> toSubSections(Vector<? extends HTMLNode> html, Iterable<DotPair> sublists)
    {
        Vector<SubSection> ret = new Vector<>();

        for (DotPair sublist : sublists)
            ret.addElement(new SubSection(sublist, toVector(html, sublist)));

        return ret;
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // List / Iterable of DotPair's to a Stream, Iterator, Array
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Convenience Method.
     * <BR />Invokes: {@link #toStream(Iterable, boolean)}
     * <BR />Converts output to an {@code Iterator}
     */
    public static PrimitiveIterator.OfInt iterator(Iterable<DotPair> dpi, boolean leastToGreatest)
    { return toStream(dpi, leastToGreatest).iterator(); }

    /**
     * Convenience Method.
     * <BR />Invokes: {@link #toStream(Iterable, boolean)}
     * <BR />Converts output to an {@code int[]} array.
     */
    public static int[] toPosArray(Iterable<DotPair> dpi, boolean leastToGreatest)
    { return toStream(dpi, leastToGreatest).toArray(); }

    /**
     * This method will convert a list of {@code DotPair} instances to a Java
     * {@code java.util.stream.IntStream}.  The generated {@code IntStream} shall contain all
     * {@code Vector}-indices (integers) that are within the bounds of any of the {@code DotPair's}
     * listed by parameter {@code 'dpi'}.
     * 
     * <BR /><BR />Stating this a second time, the returned position-index list (which is of Java
     * Type {@code IntStream}) is built out of the contents of each and every one of the the
     * {@code DotPair's} in {@code Iterable}-parameter {@code 'dpi'}.  This index-list which is
     * ultimately returned from this method <I>will contain all indices that are "inside" all
     * {@coded DotPair's}</I>.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>Repeated Indices &amp; Gaps:</B>
     * 
     * <BR />This method will never include an index more than once, and all integers in the
     * returned {@code IntStream} will be unique.
     *
     * <BR /><BR />The sublists (the {@code DotPair's} of input-parameter {@code 'dpi'}) may
     * possibly (or even 'likely') overlap each-other.  Furthermore, other {@code DotPair} /
     * sublists may have several gaps between them.  This method shall return an {@code IntStream}
     * of unique, integer indices all of which are guaranteed to be
     * <B STYLE='color: red;'><I>inside</I></B> at least one of {@code dpi's} sublists.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>NodeSearch Find 'all' Methods:</B>
     * 
     * <BR />Many of the "Find" Methods available in the {@code Torello.HTML.NodeSearch} package
     * return instances of {@code Vector<DotPair>}.  These {@code DotPair} lists are to be
     * thought-of as "lists of sub-lists" for a Vectorized-HTML web-page.  This method can help
     * identify each and every integer-index that is <I>inside at least one of these returned
     * sublists</I>.
     *
     * <BR /><BR /><B CLASS=JDDescLabel>Stale Data Reminder:</B>
     * 
     * <BR />Try to keep in mind, always, that when writing code that modifies Vectorized-HTML,
     * <I>the moment any node is inserted or deleted into a {@code Vector}</I> all references /
     * indices to that exact {@code Vector} will become invalid (unless special care is taken to
     * update those indices by the number of nodes that were inserted or removed!)
     * 
     * <BR /><BR />There are myriad ways to handle this issue, many of which are beyond the scope
     * of this Documentation Entry.  Generally, one of the better suggestions to keep in mind, is
     * that if you are modifying a Vectorized-HTML page, perform your updates or removals <I>in
     * reverse order</I>, and your {@code Vector} index-list pointers <I>will never</I> become
     * stale pointers.
     * 
     * <BR /><BR />The interface {@link Replaceable} is also another way to avoid making elementary
     * mistakes involving stale {@code Vector}-indices.
     *
     * @param dpi This may be any source for a {@code class 'Dotpair'} instance which implements
     * the public interface {@code java.lang.Iterable}.
     * 
     * @param leastToGreatest  When this parameter receives a {@code TRUE} value, the results that
     * are returned from this {@code IntStream} will be sorted least to greatest.  To generated an
     * {@code IntStream} that produces results that are sorted from greatest to least, pass
     * {@code FALSE} to this parameter.
     * 
     * @return A java {@code java.util.stream.IntStream} of the integers in that are members of
     * this {@code Iterable<DotPair>}
     */
    public static IntStream toStream(Iterable<DotPair> dpi, boolean leastToGreatest)
    {
        Iterator<DotPair>   iter    = dpi.iterator();
        TreeSet<DotPair>    ts      = new TreeSet<>();

        // The tree-set will add the "DotPair" to the tree - and keep them sorted,
        // since that's what "TreeSet" does.

        while (iter.hasNext()) ts.add(iter.next());

        Iterator<DotPair>   tsIter  = leastToGreatest ? ts.iterator() : ts.descendingIterator();
        IntStream.Builder   builder = IntStream.builder();
        DotPair             dp      = null;

        if (leastToGreatest)

            // We are building a "forward-index" stream... DO AS MUCH SORTING... AS POSSIBLE!
            while (tsIter.hasNext())
                for (int i=(dp=tsIter.next()).start; i <= dp.end; i++)
                    builder.add(i);

        else

            // we are building a "reverse-index" stream... Make sure to add the sub-lists in
            // reverse-order.

            while (tsIter.hasNext())
                for (int i=(dp=tsIter.next()).end; i >= dp.start; i--)
                    builder.add(i);

        if (leastToGreatest)

            // We have added them in order (mostly!!) - VERY-TRICKY, and this is the whole point... 
            // MULTIPLE, OVERLAPPING DOTPAIRS
            // We need to sort because the DotPair sublists have been added in "sorted order" but
            // the overall list is not (necessarily, but possibly) sorted!

            return builder.build().sorted().distinct();

        else

            // Here, the exact same argument holds, but also, when "re-sorting" we have to futz
            // around with the fact that Java's 'IntStream' class does not have a specialized
            // reverse-sort() (or alternate-sort()) method... (Kind of another JDK bug).

            return builder.build().map(i -> -i).sorted().map(i -> -i).distinct();
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // List / Iterable of DotPair's  into an "End-Poinnts" Stream, Iterator, Array
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Convenience Method.
     * <BR />Invokes: {@link #endPointsToStream(Iterable, boolean)}
     * <BR />Converts: output to an {@code Iterator}
     */
    public static PrimitiveIterator.OfInt endPointsIterator
        (Iterable<DotPair> dpi, boolean leastToGreatest)
    { return endPointsToStream(dpi, leastToGreatest).iterator(); }

    /**
     * Convenience Method.
     * <BR />Invokes: {@link #endPointsToStream(Iterable, boolean)}
     * <BR />Converts: output to an {@code int[]} array.
     */
    public static int[] endPointsToPosArray(Iterable<DotPair> dpi, boolean leastToGreatest)
    { return endPointsToStream(dpi, leastToGreatest).toArray(); }

    /**
     * Collates a list of dotted-pairs into an {@code IntStream}.  Here, only the starting and
     * ending values of the {@code DotPair's} are inserted into the returned {@code IntStream}.
     * Any indices that lay between {@code DotPair.start} and {@code DotPair.end} <I>are not
     * placed</I> into the output-{@code IntStream}.
     * 
     * <BR /><BR />All other behaviors of this method are the same as
     * {@link #toStream(Iterable, boolean)}.
     * 
     * @param dpi This may be any source for a {@code class 'Dotpair'} instance which implements
     * the public interface {@code java.lang.Iterable}.
     * 
     * @param leastToGreatest  When this parameter receives a {@code TRUE} value, the results that
     * are returned from this {@code IntStream} will be sorted least to greatest.  To generated an
     * {@code IntStream} that produces results that are sorted from greatest to least, pass
     * {@code FALSE} to this parameter.
     * 
     * @return A java {@code java.util.stream.IntStream} of the integers in that are members of
     * this {@code Iterable<DotPair>}.  Only the values {@code DotPair.start}, and
     * {@code DotPair.end} are included in the output-{@code IntStream}.  This is unlike the method
     * {@link #toStream(Iterable, boolean)} in that, here, only the starting and ending points of
     * the dotted-pair are placed into result.  In the other method, the start-index, end-index 
     * <I>and all indices in between them</I> are placed into the returned-{@code Stream}.
     * 
     * @see #toStream(Iterable, boolean)
     */
    public static IntStream endPointsToStream(Iterable<DotPair> dpi, boolean leastToGreatest)
    {
        Iterator<DotPair>   iter    = dpi.iterator();
        TreeSet<DotPair>    ts      = new TreeSet<>();

        // The tree-set will add the "DotPair" to the tree - and keep them sorted,
        // since that's what "TreeSet" does.

        while (iter.hasNext()) ts.add(iter.next());

        Iterator<DotPair>   tsIter  = leastToGreatest ? ts.iterator() : ts.descendingIterator();
        IntStream.Builder   builder = IntStream.builder();
        DotPair             dp      = null;

        if (leastToGreatest)

            // We are building a "forward-index" stream... DO AS MUCH SORTING... AS POSSIBLE!
            while (tsIter.hasNext())
            {
                dp = tsIter.next();

                // In this method, only the start/end are placed into the IntStream
                builder.add(dp.start);

                // The indices BETWEEN start/end ARE NOT appened to the IntStream
                builder.add(dp.end);
            }

        else

            // we are building a "reverse-index" stream... Make sure to add the sub-lists in
            // reverse-order.

            while (tsIter.hasNext())
            {
                dp = tsIter.next();

                // Only start/end are appended.
                builder.add(dp.end);

                // NOTE: This is a "reverse order" IntStream
                builder.add(dp.start);
            }

        if (leastToGreatest)

            // We have added them in order (mostly!!) - VERY-TRICKY, and this is the whole point...
            // MULTIPLE, OVERLAPPING DOTPAIRS
            // We need to sort because the DotPair sublists have been added in "sorted order" but
            // the overall list is not (necessarily, but possibly) sorted!

            return builder.build().sorted().distinct();

        else

            // Here, the exact same argument holds, but also, when "re-sorting" we have to futz
            // around with the fact that Java's 'IntStream' class does not have a specialized
            // reverse-sort() (or alternate-sort()) method... (Kind of another JDK bug).

            return builder.build().map(i -> -i).sorted().map(i -> -i).distinct();
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Mirror-Inverse Collated Stream, Iterator, Array
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Convenience Method.
     * <BR />Invokes: {@link #excludedToStream(Iterable, int, boolean)}
     * <BR />Converts: output to an {@code Iterator}
     */
    public static PrimitiveIterator.OfInt excludedToIterator
        (Iterable<DotPair> dpi, int vectorSize, boolean leastToGreatest)
    { return excludedToStream(dpi, vectorSize, leastToGreatest).iterator(); }

    /**
     * Convenience Method.
     * <BR />Invokes: {@link #excludedToStream(Iterable, int, boolean)}
     * <BR />Converts: output to an {@code int[]} array.
     */
    public static int[] excludedToPosArray
        (Iterable<DotPair> dpi, int vectorSize, boolean leastToGreatest)
    { return excludedToStream(dpi, vectorSize, leastToGreatest).toArray(); }

    /**
     * This method will first collate and sort a list of input {@code 'DotPair'} instances.
     * 
     * @param dpi This may be any source for a {@code class 'Dotpair'} instance which implements
     * the public interface {@code java.lang.Iterable}.
     * 
     * @param vectorSize This method internal-loop will begin at index {@code '0'} and proceed 
     * until {@code 'vectorSize' - 1}.  Any value in this range that is found not be inside any of
     * the provided {@code DotPair's} will be included inside the returned {@code IntStream}.
     * 
     * @param leastToGreatest  When this parameter receives a {@code TRUE} value, the results that
     * are returned from this {@code IntStream} will be sorted least to greatest.  To generated an
     * {@code IntStream} that produces results that are sorted from greatest to least, pass
     * {@code FALSE} to this parameter.
     * 
     * @return The list of ints
     */
    public static IntStream excludedToStream
        (Iterable<DotPair> dpi, int vectorSize, boolean leastToGreatest)
    {
        Iterator<DotPair>   iter    = dpi.iterator();
        TreeSet<DotPair>    ts      = new TreeSet<>();

        if (vectorSize < 1) throw new NException(
            "You have passed " + vectorSize + " to parameter vectorSize, but this value must be " +
            "at least 1, or greater."
        );

        // All this is going to do is MAKE SURE that the DotPair's are ordered, least to greatest
        while (iter.hasNext()) ts.add(iter.next());

        iter = leastToGreatest ? ts.iterator() : ts.descendingIterator();

        DotPair             dp  = iter.hasNext() ? iter.next() : null;
        IntStream.Builder   b   = IntStream.builder();

        if (leastToGreatest)

            for (int i=0; i < vectorSize;)

                if (dp == null)             b.accept(i++);
                else if (i < dp.start)      b.accept(i++);
                else if (dp.isInside(i))    { i++; continue; }
                else if (iter.hasNext())    Objects.requireNonNull(dp = iter.next());
                else                        dp = null;

        else 

            for (int i=(vectorSize-1); i >= 0;)

                if (dp == null)             b.accept(i--);
                else if (i < dp.start)      b.accept(i--);
                else if (dp.isInside(i))    { i--; continue; }
                else if (iter.hasNext())    Objects.requireNonNull(dp = iter.next());
                else                        dp = null;

        return b.build();
    }
}