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
package Torello.Java.JSON;

import Torello.Java.StringParse;
import Torello.Java.UnreachableError;

import Torello.Java.Function.FloatConsumer;
import Torello.Java.Function.IntIntTConsumer;
import Torello.Java.Function.IntTFunction;

import Torello.Java.Additional.EffectivelyFinal;
import Torello.Java.Additional.Counter;

import java.math.BigDecimal;

import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.IntConsumer;
import java.util.function.ObjIntConsumer;
import java.util.function.DoubleConsumer;

import javax.json.JsonArray;
import javax.json.JsonNumber;
import javax.json.JsonString;
import javax.json.JsonValue;
import javax.json.JsonObject;

import static javax.json.JsonValue.ValueType.*;
import static Torello.Java.JSON.JFlag.*;

/** <EMBED CLASS=external-html DATA-FILE-ID=SETTINGS_REC> */
public class SettingsRec<T, U>
{
    // ********************************************************************************************
    // ********************************************************************************************
    // Instance-Fields: PACKAGE-PRIVATE - These are used OUTSIDE of this class
    // ********************************************************************************************
    // ********************************************************************************************


    // Provided by User-Input, Assigned after construction, cannot be final
    // When this SettingsRec is used in conjunction withe Multi-Dimensional Array-Processor
    // this field will be assigned and re-assigned multiple times.
    // 
    // This field is THE ONLY NON-FINAL FIELD in this class!

    JsonArray ja;


    // The Main For-Loop Switch-Statement Handlers!
    // These are all used in the classes: ProcessJsonArray and JSON_ARRAY_DIMN!

    final IntConsumer                   handlerWrongType;
    final IntConsumer                   handlerNull;
    final ObjIntConsumer<JsonString>    handlerJsonString;
    final ObjIntConsumer<JsonNumber>    handlerNumber; // Added Thanksgiving 2024
    final ObjIntConsumer<JsonValue>     jsonStringWrongTypeHandler;


    // Allows the user to provide *ANY* lambda function, not just the constructor of an object
    // when attempting to handle Json-Array's which contain Objects.  This field will be null in
    // cases of building this Settings-Record instance - **UNLESS** this instance of SettingsRec is
    // being constructed for processing an array of JsonObject's.
    // 
    // ALSO, as of May 2025: There are officially two variants of the exact same "Static-Builder"
    // Lambda's / Functional-Interfaces.  BOTH of these fields are only used inside the classes
    // RJArrIntoStream & RJArrIntoConsumer - and only in the 'objArr' and 'objRec' Methods!!
    // 
    // The second 'objBuilder2' was added to allow for writing Static-Builder Methods which also
    // accept the Json-Array-Index, and the Java-Processed-Output-Index (or whatever you want to 
    // call the little 'Torello.Java.Additional.Counter' that is inserted inside the builder)

    final Function<JsonObject, T>       objBuilder;
    final IntTFunction<JsonObject, T>   objBuilder2;
    final boolean                       builder1Or2;


    // Copied directly from Helper-Class BASIC_TYPES, at the very beginning of this class
    // Constructor-Body

    final Class<T> CLASS;


    // This is the top-level "handler" for results that are to be sent to the user
    // This will either be a consumer that the user himself provided, or it will be a 
    // Stream-Acceptor method that was produced in a sub-class constructor, and passed here
    // 
    // final Consumer<T>       acceptor;
    // final ObjIntConsumer<T> acceptor2;
    // final boolean           version1OrVersion2;

    final ObjIntConsumer<T> ACCEPTOR;


    // These are only used for Stream's, **NOT** Consumer's
    // Invokes: Stream.builder(), IntStream.builder(), DoubleStream.builder(), etc...

    final Runnable constructNewBuilder;


    // These are only used for Stream's, **NOT** Consumer's
    // Invokes: Stream.Builder.build(), IntStream.Builder.build(), etc...

    final Supplier<U> runBuilderDotBuild;

    // This is only used for Multi-Dimensional Array-Processing
    final Function<JsonArray, Object> array1DGenerator;
    final boolean IN_NSAT, S_NSAT;


    // ********************************************************************************************
    // ********************************************************************************************
    // Package-Private SettingsRec Constructor
    // ********************************************************************************************
    // ********************************************************************************************


    // The very last line of this method has a cast of SettingsRec<>
    @SuppressWarnings("unchecked")
    SettingsRec(

            // Parameters passed by the user to initial query
            final T                     defaultValue,
            final int                   FLAGS,
            final Function<String, T>   userParser,

            // Configuration Stuff (Copied Directly from class "BASIC_TYPES")
            final BASIC_TYPES<T> bt,

            // Sir, Where would you prefer I shove this data?
            final Consumer<T>   acceptor,
            final Runnable      constructNewBuilder,
            final Supplier<U>   runBuilderDotBuild,

            // acceptor2: The "IntIntTConsumer" variant of an acceptor
            final IntIntTConsumer<T> acceptor2,


            // Informs this constructor how to build a 1-Dimensional Array for the
            // Multi-Dimensional Array-Processor

            final Boolean arrayGen1DRefOrPrimitive
        )
    {
        // Configurations determined by type, from class BASIC_TYES
        this.CLASS = bt.CLASS;

        // Where to send the data.  Consumer?  Stream-Builder? (and eventually a Stream or Array)
        // this.acceptor = acceptor;
        this.constructNewBuilder    = constructNewBuilder;
        this.runBuilderDotBuild     = runBuilderDotBuild;


        // This cute little thing is a "Later Addition".  It provides the second "suite" of methods
        // in the RJ Into-Consumer Series.  The user now has the option to provide a consumer that 
        // accepts the Array-Indices as well.
        // 
        // Also note, that this concept is "identical" to the Stream-Object method (inside class
        // RJArrIntoStream) which allows for a Static-Builder Lambda that accepts a Json-Object and
        // the Java Array-Indices.  However, in this portion of the code, this concept is used,
        // *STRICTLY* for the classes:
        // RJArrIntoConsumer, RJArrIntoBoxedConsumer, RJArrIntoPrimConsumer

        final boolean version1OrVersion2 = (acceptor2 == null);

        if (version1OrVersion2)
            this.ACCEPTOR = (T theValue, int ignoreThisIndex) -> acceptor.accept(theValue);
        else
        {
            final Counter javaArrayIndex = new Counter(-1);

            this.ACCEPTOR = (T theValue, int jsonArrayIndex) ->
                acceptor2.accept(jsonArrayIndex, javaArrayIndex.addOne(), theValue);
        }


        // Only used for building Multi-Dimensional Array's (rarely needed)
        this.array1DGenerator = (arrayGen1DRefOrPrimitive == null)
            ? null 
            : GENERATE_1DARRAY.retrieveAppropriateGenerator(this, bt, arrayGen1DRefOrPrimitive);


        // This is the "new thing".  It allows *ANY* lambda (not just a constructor) to produce
        // an Object of type 'T'  This field is *ALWAYS* null - *UNLESS* this instance of
        // SettingsRec is being configured to handle Json-Array's which contains objects (not one
        // of the standard primitive, number or string types).
        // 
        // Note the "Marker Boolean" is computed because these are used inside of a loop.  
        // Also, by default, if the user isn't asking for the Objects to be built, then this 
        // booean to be assigned 'false', because - in such cases - it just wouldn't matter in the
        // slightest.

        this.objBuilder     = bt.objBuilder;
        this.objBuilder2    = bt.objBuilder2;
        this.builder1Or2    = (bt.objBuilder != null);


        // This is a temporary class that is not used once this constructor has
        // completed!  Hopefully the garbage collector picks it up as soon as this is finished.
        // The "TempFlags" actually does a lot of the dispatch for deciding what handler's /
        // Lambda's are to be used when Processing a JsonArray.

        final TempFlags flags = new TempFlags(
            FLAGS,
            bt.referenceOrPrimitive,
            new Lambdas<T>(this.ACCEPTOR, defaultValue)
        );

        // Two little flags that are used by the Multi-Dimensional Array Processor
        this.IN_NSAT    = flags.IN_NSAT();
        this.S_NSAT     = flags.S_NSAT();

        this.handlerNull        = flags.selectNullHandler(this);
        this.handlerWrongType   = flags.selectWrongTypeHandler();


        // "handlerJsonString" is used for both Number-Stuff and Boolean
        // It is not Used for String or Object...
        // 
        // If you want to learn where this is used, just go to "ProcessJsonArray",
        // and you will see all of these cute little dispatch/handler dealy's hard at work

        this.handlerJsonString =
            (bt.whichType != BASIC_TYPES.STRING) && (bt.whichType != BASIC_TYPES.OBJECT)
            ? flags.selectJsonStringHandler(
                    this,
                    userParser,
                    bt.whichType,
                    bt.validStrTester,
                    bt.defaultParser
                )
            : null;


        // The field "isNumberType" is only true if this is actually used to convert a
        // a JsonNumber into a Java-Number.  This will be false for Strings, Objects & Booleans!

        this.handlerNumber = bt.isNumberType
            ? ChooseNumberHandler.choose(
                    this,
                    this.ACCEPTOR,
                    bt.whichType,
                    bt.referenceOrPrimitive,
                    bt.numberConverter,
                    bt.numberConverterExThrow,
                    bt.jsonNumWillFit,
                    flags.RJA_AEX(),
                    flags.selectAEXHandler()
                )
            : null;


        // TIf you look at "ProcessJsonArray" - this is only used for converting
        // JsonArray's of String.  All other types will never use this handler.  Therefore, in
        // any case where a User HAS NOT requested to process a JsonArray of Strings, leaving this
        // handler as 'null' will have no effect, and it certainly won't cause NullPointerException

        this.jsonStringWrongTypeHandler = (bt.whichType == BASIC_TYPES.STRING)
            ? flags.selectJsonStringWrongTypeHandler((SettingsRec<String, ?>) this)
            : null;
    }

}