001package Torello.Java.Additional;
002
003import java.util.*;
004import java.util.stream.*;
005import java.util.function.Function;
006
007import Torello.Java.FileNode;
008import Torello.Java.FileNode.RetTypeChoice; // For Java-Doc Only
009
010/**
011 * Implementation of the <CODE>FileNode</CODE> class <CODE>'RetTypeChoice'</CODE>.
012 * 
013 * <EMBED CLASS="external-html" DATA-FILE-ID=VLB_NOTE>
014 * <EMBED CLASS="external-html" DATA-FILE-ID=VLB_SORT_APPLY>
015 * 
016 * @param <ORIGINAL> This is the original data-type that is to be inserted into the list, after
017 * a simple transformation has been applied.  For class this class, the sort is applied before the
018 * transformation.
019 * 
020 * <BR /><BR />Speaking from the perspective of {@link FileNode} and {@link RetTypeChoice}
021 * the {@code 'ORIGINAL'} type is always computed to be {@code 'FileNode'}.
022 * 
023 * @param <TRANSFORMED> This is the data-type, after the transform has been applied.  The list
024 * that's returned to the user will be a container / list whose contents have type
025 * {@code 'TRANSFORMED'}.
026 * 
027 * <BR /><BR />In the case of {@link FileNode}, and {@link RetTypeChoice}, the
028 * {@code 'TRANSFORMED'} type is usually {@code java.lang.String} - <I>and the {@code String}
029 * contents are the <B>Full-Path File-Name</B>, or the <B>File-Name</B>, itself.</I>
030 */
031@SuppressWarnings("unchecked")
032public class VarListBuilderWithSortAndApply<ORIGINAL, TRANSFORMED>
033{
034    /**
035     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return a
036     * {@code Vector} whose {@code Vector}-contents are of parametrized-type {@code 'TRANSFORMED'}.
037     * The {@code Vector} returned will have already been sorted upon return.
038     */
039    public final VarList<Vector<TRANSFORMED>, ORIGINAL> VECTOR;
040
041    /**
042     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return an
043     * {@code ArrayList} whose {@code ArrayList}-contents are of parametrized-type
044     * {@code 'TRANSFORMED'}.  The {@code ArrayList} returned will have already been sorted upon
045     * return.
046     */
047    public final VarList<ArrayList<TRANSFORMED>, ORIGINAL> ARRAYLIST;
048
049    /**
050     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return an
051     * {@code Iterator} whose {@code Iterator}-contents are of parametrized-type
052     * {@code 'TRANSFORMED'}.  The {@code Iterator} returned will have already been sorted upon
053     * return.
054     */
055    public final VarList<Iterator<TRANSFORMED>, ORIGINAL> ITERATOR;
056
057    /**
058     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return an
059     * {@code array} whose {@code array}-contents are of parametrized-type {@code 'TRANSFORMED'}.
060     * The {@code array} returned will have already been sorted upon return.
061     */
062    public final VarList<TRANSFORMED[], ORIGINAL> ARRAY;
063
064    /**
065     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return a
066     * {@code Stream} whose {@code Stream}-contents are of parametrized-type {@code 'TRANSFORMED'}.
067     * The {@code Stream} returned will have already been sorted upon return.
068     */
069    public final VarList<Stream<TRANSFORMED>, ORIGINAL> STREAM;
070
071    /**
072     * Instances of {@code Stream.Builder} cannot be sorted.  Only a built {@code Stream}
073     * may be sorted.  Therefore this parameter shall always be null.
074     */
075    public final VarList<Stream.Builder<TRANSFORMED>, ORIGINAL> STREAM_BUILDER = null;
076
077    /**
078     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return a
079     * {@code LinkedList} whose {@code LinkedList}-contents are of parametrized-type
080     * {@code 'TRANSFORMED'}.  The {@code LinkedList} returned will have already been sorted upon
081     * return.
082     */
083    public final VarList<LinkedList<TRANSFORMED>, ORIGINAL> LINKEDLIST;
084
085    /**
086     * This {@code VarList} instance has a {@code 'retrieve()'} method that will return a
087     * {@code Stack} whose {@code Stack}-contents are of parametrized-type {@code 'TRANSFORMED'}.
088     * The {@code Stack} returned will have already been sorted upon return.
089     */
090    public final VarList<Stack<TRANSFORMED>, ORIGINAL> STACK;
091
092    /**
093     * Builds all 8 of the {@code VarList's} provided by this builder class.
094     * 
095     * @param comparator This is used to sort the returned list.
096     * <BR /><BR /><B><SPAN STYLE="color: red;">NOTICE:</SPAN></B> The {@code 'comparator'} is of 
097     * parametrized-type {@code 'ORIGINAL'}.  This is because the sort shall occur <B>BEFORE</B>
098     * the transform.
099     * 
100     * @param transformer This {@code transform} is used to convert the contents of the returned
101     * list-type.  As noticed by its type, {@code 'Function<ORIGINAL, TRANSFORMED>'}, the final
102     * type of the returned {@code VarList} will of type {@code 'TRANSFORMED'}, although while
103     * building this {@code 'VarList'},  the elements that shall be inserted will be of type
104     * {@code 'ORIGINAL'}.
105     *
106     *  <BR /><BR />It is the job of the transformer parameter to convert the elements from type
107     * {@code 'ORIGINAL'} to type {@code 'TRANSFORMED'}
108     * 
109     * @param outputClass The final list that is built will be of type {@code class U}.  Because
110     * java generics use "Type Erasure," this class must be obtained here.  It is  used for array
111     * generation or array-construction.
112     */
113    public VarListBuilderWithSortAndApply(
114            Comparator<ORIGINAL> comparator, Function<ORIGINAL, TRANSFORMED> transformer,
115            Class<TRANSFORMED> outputClass
116        )
117    {
118        VECTOR      = new VECTOR_CLASS      (null, comparator, transformer);
119        ARRAYLIST   = new ARRAYLIST_CLASS   (null, comparator, transformer);
120        ITERATOR    = new ITERATOR_CLASS    (null, comparator, transformer);
121        ARRAY       = new ARRAY_CLASS       (null, comparator, transformer, outputClass);
122        STREAM      = new STREAM_CLASS      (null, comparator, transformer);
123        // STREAM_BUILDER, always null, Stream.Builder cannot be sorted, only Stream
124        LINKEDLIST  = new LINKEDLIST_CLASS  (null, comparator, transformer);
125        STACK       = new STACK_CLASS       (null, comparator, transformer);
126    }
127
128    private class VECTOR_CLASS implements VarList<Vector<TRANSFORMED>, ORIGINAL>
129    {
130        private final Vector<ORIGINAL>                  v;
131        private final Comparator<ORIGINAL>              comparator;
132        private final Function<ORIGINAL, TRANSFORMED>   transformer;
133
134        public VarList<Vector<TRANSFORMED>, ORIGINAL> create()
135        { return new VECTOR_CLASS(new Vector<>(), comparator, transformer); }
136
137        public VarList<Vector<TRANSFORMED>, ORIGINAL> appendTo(Vector<TRANSFORMED> v)
138        { VarList.throwUOE2(); return null; }
139
140        public void insert(ORIGINAL original) { v.add(original); }
141
142        public Vector<TRANSFORMED> retrieve()
143        { 
144            v.sort(comparator);
145            Vector<TRANSFORMED> ret = new Vector<>(v.size());
146            v.forEach((ORIGINAL original) -> ret.add(transformer.apply(original)));
147            return ret;
148        }
149
150        VECTOR_CLASS(
151                Vector<ORIGINAL> v, Comparator<ORIGINAL> comparator,
152                Function<ORIGINAL, TRANSFORMED> transformer
153            )
154        { this.v=v; this.comparator=comparator; this.transformer=transformer; }
155    }
156
157    private class ARRAYLIST_CLASS implements VarList<ArrayList<TRANSFORMED>, ORIGINAL>
158    {
159        private final ArrayList<ORIGINAL>               al;
160        private final Comparator<ORIGINAL>              comparator;
161        private final Function<ORIGINAL, TRANSFORMED>   transformer;
162
163        public VarList<ArrayList<TRANSFORMED>, ORIGINAL> create()
164        { return new ARRAYLIST_CLASS(new ArrayList<>(), comparator, transformer); }
165
166        public VarList<ArrayList<TRANSFORMED>, ORIGINAL> appendTo(ArrayList<TRANSFORMED> al)
167        { VarList.throwUOE2(); return null; }
168
169        public void insert(ORIGINAL original) { al.add(original); }
170
171        public ArrayList<TRANSFORMED> retrieve()
172        { 
173            al.sort(comparator);
174            ArrayList<TRANSFORMED> ret = new ArrayList<>(al.size());
175            al.forEach((ORIGINAL original) -> ret.add(transformer.apply(original)));
176            return ret;
177        }
178
179        ARRAYLIST_CLASS(
180                ArrayList<ORIGINAL> al, Comparator<ORIGINAL> comparator,
181                Function<ORIGINAL, TRANSFORMED> transformer
182            )
183        { this.al=al; this.comparator=comparator; this.transformer=transformer; }
184    }
185
186    private class ITERATOR_CLASS implements VarList<Iterator<TRANSFORMED>, ORIGINAL>
187    {
188        private final Vector<ORIGINAL>                  v;
189        private final Comparator<ORIGINAL>              comparator;
190        private final Function<ORIGINAL, TRANSFORMED>   transformer;
191
192        public VarList<Iterator<TRANSFORMED>, ORIGINAL> create()
193        { return new ITERATOR_CLASS(new Vector<>(), comparator, transformer); }
194
195        public VarList<Iterator<TRANSFORMED>, ORIGINAL> appendTo(Iterator<TRANSFORMED> s)
196        { VarList.throwUOE("Iterator"); return null; }
197
198        public void insert(ORIGINAL original) { v.add(original); }
199
200        public Iterator<TRANSFORMED> retrieve()
201        { 
202            v.sort(comparator);
203            Vector<TRANSFORMED> ret = new Vector<>(v.size());
204            v.forEach((ORIGINAL original) -> ret.add(transformer.apply(original)));
205            return ret.iterator();
206        }
207
208        public ITERATOR_CLASS(
209                Vector<ORIGINAL> v, Comparator<ORIGINAL> comparator,
210                Function<ORIGINAL, TRANSFORMED> transformer
211            )
212        { this.v=v; this.comparator=comparator; this.transformer=transformer; }
213    }
214
215    private class ARRAY_CLASS implements VarList<TRANSFORMED[], ORIGINAL>
216    {
217        private final Stream.Builder<ORIGINAL>          sb;
218        private final Comparator<ORIGINAL>              comparator;
219        private final Function<ORIGINAL, TRANSFORMED>   transformer;
220        private final Class<TRANSFORMED>                outputClass;
221
222        public VarList<TRANSFORMED[], ORIGINAL> create()
223        { return new ARRAY_CLASS(Stream.builder(), comparator, transformer, outputClass); }
224
225        public VarList<TRANSFORMED[], ORIGINAL> appendTo(TRANSFORMED[] a)
226        { VarList.throwUOE("array"); return null; }
227
228        public void insert(ORIGINAL original) { sb.accept(original); }
229
230        public TRANSFORMED[] retrieve()
231        { 
232            // This idea is straight out of hell.  It does work.  The "IntFunction<TRANSFORMED[]>"
233            // is how java.util.stream.Stream deals with generic array creation.
234            //
235            // The part about java.lang.reflect.Array is copied from "Techie Delight".  It is how
236            // to implement Generic Array Creation.
237
238            java.util.function.IntFunction<TRANSFORMED[]> arrayGenerator = (int length) ->
239                (TRANSFORMED[]) java.lang.reflect.Array.newInstance(outputClass, length);
240
241            return sb.build().sorted(comparator).map((ORIGINAL original) ->
242                transformer.apply(original)).toArray(arrayGenerator);
243        }  
244
245        ARRAY_CLASS(
246                Stream.Builder<ORIGINAL> sb, Comparator<ORIGINAL> comparator,
247                Function<ORIGINAL, TRANSFORMED> transformer,Class<TRANSFORMED> outputClass
248            )
249        {
250            this.sb=sb;
251            this.comparator=comparator;
252            this.transformer=transformer;
253            this.outputClass=outputClass;
254        }
255    }
256
257    private class STREAM_CLASS implements VarList<Stream<TRANSFORMED>, ORIGINAL>
258    {
259        private final Stream.Builder<ORIGINAL>          sb;
260        private final Comparator<ORIGINAL>              comparator;
261        private final Function<ORIGINAL, TRANSFORMED>   transformer;
262
263        public VarList<Stream<TRANSFORMED>, ORIGINAL> create()
264        { return new STREAM_CLASS(Stream.builder(), comparator, transformer); }
265
266        public VarList<Stream<TRANSFORMED>, ORIGINAL> appendTo(Stream<TRANSFORMED> s)
267        { VarList.throwUOE("Stream"); return null; }
268
269        public void insert(ORIGINAL original) { sb.accept(original); }
270
271        public Stream<TRANSFORMED> retrieve()
272        {
273            return sb.build().sorted(comparator).map((ORIGINAL original) ->
274                transformer.apply(original));
275        }
276
277        STREAM_CLASS(
278                Stream.Builder<ORIGINAL> sb, Comparator<ORIGINAL> comparator,
279                Function<ORIGINAL, TRANSFORMED> transformer
280            )
281        { this.sb=sb; this.comparator=comparator; this.transformer=transformer; }
282    }
283
284    private class LINKEDLIST_CLASS implements VarList<LinkedList<TRANSFORMED>, ORIGINAL>
285    {
286        private final LinkedList<ORIGINAL>              ll;
287        private final Comparator<ORIGINAL>              comparator;
288        private final Function<ORIGINAL, TRANSFORMED>   transformer;
289
290        public VarList<LinkedList<TRANSFORMED>, ORIGINAL> create()
291        { return new LINKEDLIST_CLASS(new LinkedList<>(), comparator, transformer); }
292
293        public VarList<LinkedList<TRANSFORMED>, ORIGINAL> appendTo(LinkedList<TRANSFORMED> ll)
294        { VarList.throwUOE2(); return null; }
295
296        public void insert(ORIGINAL original) { ll.add(original); }
297
298        public LinkedList<TRANSFORMED> retrieve()
299        { 
300            ll.sort(comparator);
301            LinkedList<TRANSFORMED> ret = new LinkedList<>();
302            ll.forEach((ORIGINAL original) -> ret.add(transformer.apply(original)));
303            return ret;
304        }
305
306        LINKEDLIST_CLASS(
307                LinkedList<ORIGINAL> ll, Comparator<ORIGINAL> comparator,
308                Function<ORIGINAL, TRANSFORMED> transformer
309            )
310        { this.ll=ll; this.comparator=comparator; this.transformer=transformer; }
311    }
312
313    private class STACK_CLASS implements VarList<Stack<TRANSFORMED>, ORIGINAL>
314    {
315        private final Stack<ORIGINAL>                   s;
316        private final Comparator<ORIGINAL>              comparator;
317        private final Function<ORIGINAL, TRANSFORMED>   transformer;
318
319        public VarList<Stack<TRANSFORMED>, ORIGINAL> create()
320        { return new STACK_CLASS(new Stack<>(), comparator, transformer); }
321
322        public VarList<Stack<TRANSFORMED>, ORIGINAL> appendTo(Stack<TRANSFORMED> s)
323        { VarList.throwUOE2(); return null; }
324
325        public void insert(ORIGINAL original) { s.push(original); }
326
327        public Stack<TRANSFORMED> retrieve()
328        { 
329            s.sort(comparator);
330            Stack<TRANSFORMED> ret = new Stack<>();
331            s.forEach((ORIGINAL original) -> ret.add(transformer.apply(original)));
332            return ret;
333        }
334
335        STACK_CLASS(
336                Stack<ORIGINAL> s, Comparator<ORIGINAL> comparator,
337                Function<ORIGINAL, TRANSFORMED> transformer
338            )
339        { this.s=s; this.comparator=comparator; this.transformer=transformer; }
340    }
341}