001package Torello.Java.JSON;
002
003import Torello.Java.StringParse;
004import Torello.Java.UnreachableError;
005
006import Torello.Java.Function.FloatConsumer;
007import Torello.Java.Function.IntIntTConsumer;
008import Torello.Java.Function.IntTFunction;
009
010import Torello.Java.Additional.EffectivelyFinal;
011import Torello.Java.Additional.Counter;
012
013import java.math.BigDecimal;
014
015import java.util.function.Consumer;
016import java.util.function.Supplier;
017import java.util.function.Function;
018import java.util.function.Predicate;
019import java.util.function.IntConsumer;
020import java.util.function.ObjIntConsumer;
021import java.util.function.DoubleConsumer;
022
023import javax.json.JsonArray;
024import javax.json.JsonNumber;
025import javax.json.JsonString;
026import javax.json.JsonValue;
027import javax.json.JsonObject;
028
029import static javax.json.JsonValue.ValueType.*;
030import static Torello.Java.JSON.JFlag.*;
031
032/** <EMBED CLASS=external-html DATA-FILE-ID=SETTINGS_REC> */
033public class SettingsRec<T, U>
034{
035    // ********************************************************************************************
036    // ********************************************************************************************
037    // Instance-Fields: PACKAGE-PRIVATE - These are used OUTSIDE of this class
038    // ********************************************************************************************
039    // ********************************************************************************************
040
041
042    // Provided by User-Input, Assigned after construction, cannot be final
043    // When this SettingsRec is used in conjunction withe Multi-Dimensional Array-Processor
044    // this field will be assigned and re-assigned multiple times.
045    // 
046    // This field is THE ONLY NON-FINAL FIELD in this class!
047
048    JsonArray ja;
049
050
051    // The Main For-Loop Switch-Statement Handlers!
052    // These are all used in the classes: ProcessJsonArray and JSON_ARRAY_DIMN!
053
054    final IntConsumer                   handlerWrongType;
055    final IntConsumer                   handlerNull;
056    final ObjIntConsumer<JsonString>    handlerJsonString;
057    final ObjIntConsumer<JsonNumber>    handlerNumber; // Added Thanksgiving 2024
058    final ObjIntConsumer<JsonValue>     jsonStringWrongTypeHandler;
059
060
061    // Allows the user to provide *ANY* lambda function, not just the constructor of an object
062    // when attempting to handle Json-Array's which contain Objects.  This field will be null in
063    // cases of building this Settings-Record instance - **UNLESS** this instance of SettingsRec is
064    // being constructed for processing an array of JsonObject's.
065    // 
066    // ALSO, as of May 2025: There are officially two variants of the exact same "Static-Builder"
067    // Lambda's / Functional-Interfaces.  BOTH of these fields are only used inside the classes
068    // RJArrIntoStream & RJArrIntoConsumer - and only in the 'objArr' and 'objRec' Methods!!
069    // 
070    // The second 'objBuilder2' was added to allow for writing Static-Builder Methods which also
071    // accept the Json-Array-Index, and the Java-Processed-Output-Index (or whatever you want to 
072    // call the little 'Torello.Java.Additional.Counter' that is inserted inside the builder)
073
074    final Function<JsonObject, T>       objBuilder;
075    final IntTFunction<JsonObject, T>   objBuilder2;
076    final boolean                       builder1Or2;
077
078
079    // Copied directly from Helper-Class BASIC_TYPES, at the very beginning of this class
080    // Constructor-Body
081
082    final Class<T> CLASS;
083
084
085    // This is the top-level "handler" for results that are to be sent to the user
086    // This will either be a consumer that the user himself provided, or it will be a 
087    // Stream-Acceptor method that was produced in a sub-class constructor, and passed here
088    // 
089    // final Consumer<T>       acceptor;
090    // final ObjIntConsumer<T> acceptor2;
091    // final boolean           version1OrVersion2;
092
093    final ObjIntConsumer<T> ACCEPTOR;
094
095
096    // These are only used for Stream's, **NOT** Consumer's
097    // Invokes: Stream.builder(), IntStream.builder(), DoubleStream.builder(), etc...
098
099    final Runnable constructNewBuilder;
100
101
102    // These are only used for Stream's, **NOT** Consumer's
103    // Invokes: Stream.Builder.build(), IntStream.Builder.build(), etc...
104
105    final Supplier<U> runBuilderDotBuild;
106
107    // This is only used for Multi-Dimensional Array-Processing
108    final Function<JsonArray, Object> array1DGenerator;
109    final boolean IN_NSAT, S_NSAT;
110
111
112    // ********************************************************************************************
113    // ********************************************************************************************
114    // Package-Private SettingsRec Constructor
115    // ********************************************************************************************
116    // ********************************************************************************************
117
118
119    // The very last line of this method has a cast of SettingsRec<>
120    @SuppressWarnings("unchecked")
121    SettingsRec(
122
123            // Parameters passed by the user to initial query
124            final T                     defaultValue,
125            final int                   FLAGS,
126            final Function<String, T>   userParser,
127
128            // Configuration Stuff (Copied Directly from class "BASIC_TYPES")
129            final BASIC_TYPES<T> bt,
130
131            // Sir, Where would you prefer I shove this data?
132            final Consumer<T>   acceptor,
133            final Runnable      constructNewBuilder,
134            final Supplier<U>   runBuilderDotBuild,
135
136            // acceptor2: The "IntIntTConsumer" variant of an acceptor
137            final IntIntTConsumer<T> acceptor2,
138
139
140            // Informs this constructor how to build a 1-Dimensional Array for the
141            // Multi-Dimensional Array-Processor
142
143            final Boolean arrayGen1DRefOrPrimitive
144        )
145    {
146        // Configurations determined by type, from class BASIC_TYES
147        this.CLASS = bt.CLASS;
148
149        // Where to send the data.  Consumer?  Stream-Builder? (and eventually a Stream or Array)
150        // this.acceptor = acceptor;
151        this.constructNewBuilder    = constructNewBuilder;
152        this.runBuilderDotBuild     = runBuilderDotBuild;
153
154
155        // This cute little thing is a "Later Addition".  It provides the second "suite" of methods
156        // in the RJ Into-Consumer Series.  The user now has the option to provide a consumer that 
157        // accepts the Array-Indices as well.
158        // 
159        // Also note, that this concept is "identical" to the Stream-Object method (inside class
160        // RJArrIntoStream) which allows for a Static-Builder Lambda that accepts a Json-Object and
161        // the Java Array-Indices.  However, in this portion of the code, this concept is used,
162        // *STRICTLY* for the classes:
163        // RJArrIntoConsumer, RJArrIntoBoxedConsumer, RJArrIntoPrimConsumer
164
165        final boolean version1OrVersion2 = (acceptor2 == null);
166
167        if (version1OrVersion2)
168            this.ACCEPTOR = (T theValue, int ignoreThisIndex) -> acceptor.accept(theValue);
169        else
170        {
171            final Counter javaArrayIndex = new Counter(-1);
172
173            this.ACCEPTOR = (T theValue, int jsonArrayIndex) ->
174                acceptor2.accept(jsonArrayIndex, javaArrayIndex.addOne(), theValue);
175        }
176
177
178        // Only used for building Multi-Dimensional Array's (rarely needed)
179        this.array1DGenerator = (arrayGen1DRefOrPrimitive == null)
180            ? null 
181            : GENERATE_1DARRAY.retrieveAppropriateGenerator(this, bt, arrayGen1DRefOrPrimitive);
182
183
184        // This is the "new thing".  It allows *ANY* lambda (not just a constructor) to produce
185        // an Object of type 'T'  This field is *ALWAYS* null - *UNLESS* this instance of
186        // SettingsRec is being configured to handle Json-Array's which contains objects (not one
187        // of the standard primitive, number or string types).
188        // 
189        // Note the "Marker Boolean" is computed because these are used inside of a loop.  
190        // Also, by default, if the user isn't asking for the Objects to be built, then this 
191        // booean to be assigned 'false', because - in such cases - it just wouldn't matter in the
192        // slightest.
193
194        this.objBuilder     = bt.objBuilder;
195        this.objBuilder2    = bt.objBuilder2;
196        this.builder1Or2    = (bt.objBuilder != null);
197
198
199        // This is a temporary class that is not used once this constructor has
200        // completed!  Hopefully the garbage collector picks it up as soon as this is finished.
201        // The "TempFlags" actually does a lot of the dispatch for deciding what handler's /
202        // Lambda's are to be used when Processing a JsonArray.
203
204        final TempFlags flags = new TempFlags(
205            FLAGS,
206            bt.referenceOrPrimitive,
207            new Lambdas<T>(this.ACCEPTOR, defaultValue)
208        );
209
210        // Two little flags that are used by the Multi-Dimensional Array Processor
211        this.IN_NSAT    = flags.IN_NSAT();
212        this.S_NSAT     = flags.S_NSAT();
213
214        this.handlerNull        = flags.selectNullHandler(this);
215        this.handlerWrongType   = flags.selectWrongTypeHandler();
216
217
218        // "handlerJsonString" is used for both Number-Stuff and Boolean
219        // It is not Used for String or Object...
220        // 
221        // If you want to learn where this is used, just go to "ProcessJsonArray",
222        // and you will see all of these cute little dispatch/handler dealy's hard at work
223
224        this.handlerJsonString =
225            (bt.whichType != BASIC_TYPES.STRING) && (bt.whichType != BASIC_TYPES.OBJECT)
226            ? flags.selectJsonStringHandler(
227                    this,
228                    userParser,
229                    bt.whichType,
230                    bt.validStrTester,
231                    bt.defaultParser
232                )
233            : null;
234
235
236        // The field "isNumberType" is only true if this is actually used to convert a
237        // a JsonNumber into a Java-Number.  This will be false for Strings, Objects & Booleans!
238
239        this.handlerNumber = bt.isNumberType
240            ? ChooseNumberHandler.choose(
241                    this,
242                    this.ACCEPTOR,
243                    bt.whichType,
244                    bt.referenceOrPrimitive,
245                    bt.numberConverter,
246                    bt.numberConverterExThrow,
247                    bt.jsonNumWillFit,
248                    flags.RJA_AEX(),
249                    flags.selectAEXHandler()
250                )
251            : null;
252
253
254        // TIf you look at "ProcessJsonArray" - this is only used for converting
255        // JsonArray's of String.  All other types will never use this handler.  Therefore, in
256        // any case where a User HAS NOT requested to process a JsonArray of Strings, leaving this
257        // handler as 'null' will have no effect, and it certainly won't cause NullPointerException
258
259        this.jsonStringWrongTypeHandler = (bt.whichType == BASIC_TYPES.STRING)
260            ? flags.selectJsonStringWrongTypeHandler((SettingsRec<String, ?>) this)
261            : null;
262    }
263
264}