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

import java.util.function.Predicate;
import java.util.function.Function;
import java.util.function.ObjIntConsumer;
import java.util.function.IntConsumer;

import javax.json.JsonString;
import javax.json.JsonValue;

import static javax.json.JsonValue.ValueType.NUMBER;
import static javax.json.JsonValue.ValueType.STRING;

import static Torello.Java.JSON.JFlag.*;

// An (extremely) temporary class.  This is created in the SettingsRec Constructor, and then it is
// GC'ed as soon as that Constructor finishes.
// 
// IMPORTANT NOTE: These booleans are used to decide WHICH Lambda to return.  These boolean's 
//                 ARE NEVER used inside of a Lambda - which (if you try really had to think about 
//                 it) means the GC will not retain or keep these once the SettingsRec Constructor
//                 has finished.
// 
// 
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// The 'ja' instance declared in class "SettingsRec" **IS NOT** declared final.  It can be reset !
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 
// IMPORTANT NOTE: The 'ja' that is passed to the Functional-Interface Implementatons which are 
// constructed in this method is "de-referenced" from the SettingsRec -- It **IS NOT** passed as
// a parameter to this method.  If it **WERE NOT** retrieved from the 'SettingsRec', then 'sr'
// instance, then the 'ja' that would be used would be permanently-solidified to the 'ja' 
// referenced that were passed right at the beginning, upon construction of the SettingsRec
// instance.

class TempFlags
{
    // Internally used flags.  These are actually only used during the construction phase, and 
    // therefore these don't have to be "instance fields" at all, they could easily just be final
    // variables that are used (and then discarded) inside of the constructor only.  However, since
    // there has been a recent "Breaking up the Monolithic Constructor" into smaller pieces, these
    // were moved here.
    // 
    // These could also, EASILY, be final-variables that are passed as parameters into the methods 
    // that use them, but this seems OK.  The garbage collector really won't know the difference,
    // because these are primitives.

    private final boolean NULLS, RN_AA, RD_AA, S_AA;

    // Some of the FLAGS.
    private final boolean RTS_WT, RJA_AEX, IN_NSAT, S_NSAT;

    // A Quick Getter for three of the above private fields
    boolean RJA_AEX()   { return this.RJA_AEX;  }
    boolean IN_NSAT()   { return this.IN_NSAT;  }
    boolean S_NSAT()    { return this.S_NSAT;   }

    // Save the actual-complete FLAGS Mask
    private final int FLAGS;

    @SuppressWarnings("rawtypes")
    private final Lambdas lambdas;

    TempFlags(
            final int       FLAGS,
            final boolean   NULLS,

            @SuppressWarnings("rawtypes")
            final Lambdas lambdas
        )
    {
        this.RJA_AEX    = (FLAGS & RETURN_JAPPROX_ON_AEX) > 0;
        this.RTS_WT     = (FLAGS & RETURN_TOSTRING_ON_WRONGTYPE) > 0;
        this.IN_NSAT    = (FLAGS & INSERT_NULL_ON_NON_SUBARRAY_TYPE) > 0;
        this.S_NSAT     = (FLAGS & SKIP_ON_NON_SUBARRAY_TYPE) > 0;


        // Fields which are (only) used in the "Handler Selector Methods" below
        // These could be converted into Final-Variables that are passed as parameters into the
        // Selector-Methods below, but I chose not too.  I don't have a good reason.  The way it is
        // being done, now, is a tiny bit wasteful since they are now saved as Final / Constant
        // Fields in this class, but they are private and aren't ever used after this constructor
        // finishes!
        // 
        // Passing them as a long list of parameters to each of the selector methods would also be
        // a "Tiny Bit" slower!

        this.NULLS = NULLS;
        this.RN_AA = NULLS && ((FLAGS & RETURN_NULL_ON_ANY_ALL) > 0);
        this.RD_AA = (FLAGS & RETURN_DEFVAL_ON_ANY_ALL) > 0;
        this.S_AA  = (FLAGS & SKIP_ON_ANY_ALL) > 0;

        this.FLAGS      = FLAGS;
        this.lambdas    = lambdas;
    }


    // Used when Json-Null is encountered in a Json-Array
    IntConsumer selectNullHandler(final SettingsRec<?, ?> sr)
    {
        if (NULLS && ((FLAGS & RETURN_NULL_ON_NULL) > 0))   return lambdas::AN;
        else if ((FLAGS & RETURN_DEFVAL_ON_NULL) > 0)       return lambdas::AD;
        else if ((FLAGS & SKIP_ON_NULL) > 0)                return lambdas::NOOP;
        else if (NULLS && RN_AA)                            return lambdas::AN;
        else if (RD_AA)                                     return lambdas::AD;
        else if (S_AA)                                      return lambdas::NOOP;
        else if (NULLS)                                     return lambdas::AN;


        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
        // versus 'ja' (being passed as a parameter to this method).

        else return (int i) ->
            { throw new JsonNullPrimitiveArrException(sr.ja, i, NUMBER, sr.CLASS); };
    }

    // AEX Handler (ArithmeticException)
    IntConsumer selectAEXHandler()
    {
        if (NULLS && ((FLAGS & RETURN_NULL_ON_AEX) > 0))    return lambdas::AN;
        else if ((FLAGS & RETURN_DEFVAL_ON_AEX) > 0)        return lambdas::AD;
        else if ((FLAGS & SKIP_ON_AEX) > 0)                 return lambdas::NOOP;
        else if (NULLS && RN_AA)                            return lambdas::AN;
        else if (RD_AA)                                     return lambdas::AD;
        else if (S_AA)                                      return lambdas::NOOP;

        return null;
    }

    // SPEX Handler (Exception while parsing a String into the Java-Type)
    private IntConsumer selectSPEXHandler()
    {
        if (NULLS && ((FLAGS & RETURN_NULL_ON_SPEX) > 0))   return lambdas::AN;
        else if ((FLAGS & RETURN_DEFVAL_ON_SPEX) > 0)       return lambdas::AD;
        else if ((FLAGS & SKIP_ON_SPEX) > 0)                return lambdas::NOOP;
        else if (NULLS && RN_AA)                            return lambdas::AN;
        else if (RD_AA)                                     return lambdas::AD;
        else if (S_AA)                                      return lambdas::NOOP;

        return null;
    }

    // ZLS Handler (A Zero-Length String was in the JsonArray)
    private IntConsumer selectZLSHandler()
    {
        if (NULLS && ((FLAGS & RETURN_NULL_ON_0LEN_STR) > 0))   return lambdas::AN;
        else if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) > 0)       return lambdas::AD;
        else if ((FLAGS & SKIP_ON_0LEN_STR) > 0)                return lambdas::NOOP;
        else if (NULLS && RN_AA)                                return lambdas::AN;
        else if (RD_AA)                                         return lambdas::AD;
        else if (S_AA)                                          return lambdas::NOOP;

        return null;
    }

    // Wrong-Type Handler (A JsonObject or a nested-JsonArray was in an array position)
    IntConsumer selectWrongTypeHandler()
    {
        if (NULLS && ((FLAGS & RN_WT) > 0))             return lambdas::AN;
        else if ((FLAGS & RD_WT) > 0)                   return lambdas::AD;
        else if ((FLAGS & SKIP_ON_WRONG_JSONTYPE) > 0)  return lambdas::NOOP;
        else if (NULLS && RN_AA)                        return lambdas::AN;
        else if (RD_AA)                                 return lambdas::AD;
        else if (S_AA)                                  return lambdas::NOOP;

        return null;
    }


    // JsonString Handler: **ONLY USED BY** ProcessJsonArray.numericToJava
    <T> ObjIntConsumer<JsonString> selectJsonStringHandler(
            final SettingsRec<T, ?>     sr,
            final Function<String, T>   userParser,

            // BASIC_TYPES: bt.whichType,
            final byte whichType,

            // BASIC_TYPES: bt.validStrTester,
            final Predicate<String> validStrTester,

            // BASIC_TYPES: bt.defaultParser
            final Function<String, T> defaultParser
        )
    {
        final IntConsumer handlerSPEX  = this.selectSPEXHandler();
        final IntConsumer handlerZLS   = this.selectZLSHandler();

        if (userParser != null)
            return ChooseStringHandler.useUserParser
                (sr, sr.CLASS, sr.ACCEPTOR, userParser, handlerSPEX);

        else if ((FLAGS & RP_S) > 0) return (whichType == BASIC_TYPES.NUMBER)

            ? ChooseStringHandler.parseStringNUMBER
                (sr, sr.CLASS, sr.ACCEPTOR, handlerSPEX, handlerZLS)

            : ChooseStringHandler.parseString(
                sr, sr.CLASS, sr.ACCEPTOR,
                handlerSPEX, handlerZLS, validStrTester, defaultParser
            );

        else if (NULLS && ((FLAGS & RETURN_NULL_ON_STR) > 0))   return lambdas::AN;
        else if ((FLAGS & RETURN_DEFVAL_ON_STR) > 0)            return lambdas::AD;
        else if ((FLAGS & SKIP_ON_STR) > 0)                     return lambdas::NOOP;
        else if (NULLS && RN_AA)                                return lambdas::AN;
        else if (RD_AA)                                         return lambdas::AD;
        else if (S_AA)                                          return lambdas::NOOP;

        // Thanksgiving 2024
        else if (sr.handlerWrongType != null)
            return (JsonString js, int i) -> sr.handlerWrongType.accept(i);


        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
        // versus 'ja' (being passed as a parameter to this method).

        else return (JsonString js, int i) ->
            { throw new JsonTypeArrException (sr.ja, i, NUMBER, js, sr.CLASS); };
    }

    <T> ObjIntConsumer<JsonValue> selectJsonStringWrongTypeHandler
        (final SettingsRec<String, ?> sr)
    {
        if (this.RTS_WT)
            return (JsonValue jv, int i) -> sr.ACCEPTOR.accept(jv.toString(), i);

        else if (sr.handlerWrongType != null)
            return (JsonValue jv, int i) -> sr.handlerWrongType.accept(i);


        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
        // versus 'ja' (being passed as a parameter to this method).

        else return (JsonValue jv, int i) ->
            { throw new JsonTypeArrException(sr.ja, i, STRING, jv, String.class); };
    }
}