001package Torello.JSON;
002
003import java.util.function.Predicate;
004import java.util.function.Function;
005import java.util.function.ObjIntConsumer;
006import java.util.function.IntConsumer;
007
008import javax.json.JsonString;
009import javax.json.JsonValue;
010
011import static javax.json.JsonValue.ValueType.NUMBER;
012import static javax.json.JsonValue.ValueType.STRING;
013
014import static Torello.JSON.JFlag.*;
015
016// An (extremely) temporary class.  This is created in the SettingsRec Constructor, and then it is
017// GC'ed as soon as that Constructor finishes.
018// 
019// IMPORTANT NOTE: These booleans are used to decide WHICH Lambda to return.  These boolean's 
020//                 ARE NEVER used inside of a Lambda - which (if you try really had to think about 
021//                 it) means the GC will not retain or keep these once the SettingsRec Constructor
022//                 has finished.
023// 
024// 
025// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
026// The 'ja' instance declared in class "SettingsRec" **IS NOT** declared final.  It can be reset !
027// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
028// 
029// IMPORTANT NOTE: The 'ja' that is passed to the Functional-Interface Implementatons which are 
030// constructed in this method is "de-referenced" from the SettingsRec -- It **IS NOT** passed as
031// a parameter to this method.  If it **WERE NOT** retrieved from the 'SettingsRec', then 'sr'
032// instance, then the 'ja' that would be used would be permanently-solidified to the 'ja' 
033// referenced that were passed right at the beginning, upon construction of the SettingsRec
034// instance.
035
036public class FlagsToHandler<T>
037{
038    // Internally used flags.  These are actually only used during the construction phase, and 
039    // therefore these don't have to be "instance fields" at all, they could easily just be final
040    // variables that are used (and then discarded) inside of the constructor only.  However, since
041    // there has been a recent "Breaking up the Monolithic Constructor" into smaller pieces, these
042    // were moved here.
043    // 
044    // These could also, EASILY, be final-variables that are passed as parameters into the methods 
045    // that use them, but this seems OK.  The garbage collector really won't know the difference,
046    // because these are primitives.
047
048    private final boolean NULLS, RN_AA, RD_AA, S_AA;
049
050    // Some of the FLAGS.
051    private final boolean RTS_WT, RJA_AEX, IN_NSAT, S_NSAT;
052
053    // A Quick Getter for three of the above private fields
054    boolean RJA_AEX()   { return this.RJA_AEX;  }
055    boolean IN_NSAT()   { return this.IN_NSAT;  }
056    boolean S_NSAT()    { return this.S_NSAT;   }
057
058    // Save the actual-complete FLAGS Mask
059    private final int FLAGS;
060
061    private final ACCEPTOR<T> acceptor;
062
063    FlagsToHandler(
064            final int           FLAGS,
065            final boolean       NULLS,
066            final ACCEPTOR<T>   acceptor
067        )
068    {
069        this.RJA_AEX    = (FLAGS & RETURN_JAPPROX_ON_AEX) > 0;
070        this.RTS_WT     = (FLAGS & RETURN_TOSTRING_ON_WRONGTYPE) > 0;
071        this.IN_NSAT    = (FLAGS & INSERT_NULL_ON_NON_SUBARRAY_TYPE) > 0;
072        this.S_NSAT     = (FLAGS & SKIP_ON_NON_SUBARRAY_TYPE) > 0;
073
074
075        // Fields which are (only) used in the "Handler Selector Methods" below
076        // These could be converted into Final-Variables that are passed as parameters into the
077        // Selector-Methods below, but I chose not too.  I don't have a good reason.  The way it is
078        // being done, now, is a tiny bit wasteful since they are now saved as Final / Constant
079        // Fields in this class, but they are private and aren't ever used after this constructor
080        // finishes!
081        // 
082        // Passing them as a long list of parameters to each of the selector methods would also be
083        // a "Tiny Bit" slower!
084
085        this.NULLS = NULLS;
086        this.RN_AA = NULLS && ((FLAGS & RETURN_NULL_ON_ANY_ALL) > 0);
087        this.RD_AA = (FLAGS & RETURN_DEFVAL_ON_ANY_ALL) > 0;
088        this.S_AA  = (FLAGS & SKIP_ON_ANY_ALL) > 0;
089
090        this.FLAGS      = FLAGS;
091        this.acceptor   = acceptor;
092    }
093
094
095    // Used when Json-Null is encountered in a Json-Array
096    IntConsumer selectNullHandler(final SettingsRec<?, ?> sr)
097    {
098        if (NULLS && ((FLAGS & RETURN_NULL_ON_NULL) > 0))   return acceptor::AN;
099        else if ((FLAGS & RETURN_DEFVAL_ON_NULL) > 0)       return this.acceptor::AD;
100        else if ((FLAGS & SKIP_ON_NULL) > 0)                return this.acceptor::NOOP;
101        else if (NULLS && RN_AA)                            return this.acceptor::AN;
102        else if (RD_AA)                                     return this.acceptor::AD;
103        else if (S_AA)                                      return this.acceptor::NOOP;
104        else if (NULLS)                                     return this.acceptor::AN;
105
106
107        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
108        // versus 'ja' (being passed as a parameter to this method).
109
110        else return (int i) ->
111            { throw new JsonNullPrimitiveArrException(sr.ja, i, NUMBER, sr.CLASS); };
112    }
113
114    // AEX Handler (ArithmeticException)
115    IntConsumer selectAEXHandler()
116    {
117        if (NULLS && ((FLAGS & RETURN_NULL_ON_AEX) > 0))    return this.acceptor::AN;
118        else if ((FLAGS & RETURN_DEFVAL_ON_AEX) > 0)        return this.acceptor::AD;
119        else if ((FLAGS & SKIP_ON_AEX) > 0)                 return this.acceptor::NOOP;
120        else if (NULLS && RN_AA)                            return this.acceptor::AN;
121        else if (RD_AA)                                     return this.acceptor::AD;
122        else if (S_AA)                                      return this.acceptor::NOOP;
123
124        return null;
125    }
126
127    // SPEX Handler (Exception while parsing a String into the Java-Type)
128    private IntConsumer selectSPEXHandler()
129    {
130        if (NULLS && ((FLAGS & RETURN_NULL_ON_SPEX) > 0))   return this.acceptor::AN;
131        else if ((FLAGS & RETURN_DEFVAL_ON_SPEX) > 0)       return this.acceptor::AD;
132        else if ((FLAGS & SKIP_ON_SPEX) > 0)                return this.acceptor::NOOP;
133        else if (NULLS && RN_AA)                            return this.acceptor::AN;
134        else if (RD_AA)                                     return this.acceptor::AD;
135        else if (S_AA)                                      return this.acceptor::NOOP;
136
137        return null;
138    }
139
140    // ZLS Handler (A Zero-Length String was in the JsonArray)
141    private IntConsumer selectZLSHandler()
142    {
143        if (NULLS && ((FLAGS & RETURN_NULL_ON_0LEN_STR) > 0))   return this.acceptor::AN;
144        else if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) > 0)       return this.acceptor::AD;
145        else if ((FLAGS & SKIP_ON_0LEN_STR) > 0)                return this.acceptor::NOOP;
146        else if (NULLS && RN_AA)                                return this.acceptor::AN;
147        else if (RD_AA)                                         return this.acceptor::AD;
148        else if (S_AA)                                          return this.acceptor::NOOP;
149
150        return null;
151    }
152
153    // Wrong-Type Handler (A JsonObject or a nested-JsonArray was in an array position)
154    IntConsumer selectWrongTypeHandler()
155    {
156        if (NULLS && ((FLAGS & RN_WT) > 0))             return this.acceptor::AN;
157        else if ((FLAGS & RD_WT) > 0)                   return this.acceptor::AD;
158        else if ((FLAGS & SKIP_ON_WRONG_JSONTYPE) > 0)  return this.acceptor::NOOP;
159        else if (NULLS && RN_AA)                        return this.acceptor::AN;
160        else if (RD_AA)                                 return this.acceptor::AD;
161        else if (S_AA)                                  return this.acceptor::NOOP;
162
163        return null;
164    }
165
166
167    // JsonString Handler: **ONLY USED BY** ProcessJsonArray.numericToJava
168    <T> ObjIntConsumer<JsonString> selectJsonStringHandler(
169            final SettingsRec<T, ?>     sr,
170            final Function<String, T>   userParser,
171
172            // BASIC_TYPES: bt.whichType,
173            final byte whichType,
174
175            // BASIC_TYPES: bt.validStrTester,
176            final Predicate<String> validStrTester,
177
178            // BASIC_TYPES: bt.defaultParser
179            final Function<String, T> defaultParser
180        )
181    {
182        final IntConsumer handlerSPEX  = this.selectSPEXHandler();
183        final IntConsumer handlerZLS   = this.selectZLSHandler();
184
185        if (userParser != null)
186            return ChooseStringHandler.useUserParser
187                (sr, sr.CLASS, sr.acceptor, userParser, handlerSPEX);
188
189        else if ((FLAGS & RP_S) > 0) return (whichType == BASIC_TYPES.NUMBER)
190
191            ? ChooseStringHandler.parseStringNUMBER
192                (sr, sr.CLASS, sr.acceptor, handlerSPEX, handlerZLS)
193
194            : ChooseStringHandler.parseString(
195                sr, sr.CLASS, sr.acceptor,
196                handlerSPEX, handlerZLS, validStrTester, defaultParser
197            );
198
199        else if (NULLS && ((FLAGS & RETURN_NULL_ON_STR) > 0))   return this.acceptor::AN;
200        else if ((FLAGS & RETURN_DEFVAL_ON_STR) > 0)            return this.acceptor::AD;
201        else if ((FLAGS & SKIP_ON_STR) > 0)                     return this.acceptor::NOOP;
202        else if (NULLS && RN_AA)                                return this.acceptor::AN;
203        else if (RD_AA)                                         return this.acceptor::AD;
204        else if (S_AA)                                          return this.acceptor::NOOP;
205
206        // Thanksgiving 2024
207        else if (sr.handlerWrongType != null)
208            return (JsonString js, int i) -> sr.handlerWrongType.accept(i);
209
210
211        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
212        // versus 'ja' (being passed as a parameter to this method).
213
214        else return (JsonString js, int i) ->
215            { throw new JsonTypeArrException (sr.ja, i, NUMBER, js, sr.CLASS); };
216    }
217
218    <T> ObjIntConsumer<JsonValue> selectJsonStringWrongTypeHandler
219        (final SettingsRec<String, ?> sr)
220    {
221        if (this.RTS_WT)
222            return (JsonValue jv, int i) -> sr.acceptor.accept(jv.toString(), i);
223
224        else if (sr.handlerWrongType != null)
225            return (JsonValue jv, int i) -> sr.handlerWrongType.accept(i);
226
227
228        // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
229        // versus 'ja' (being passed as a parameter to this method).
230
231        else return (JsonValue jv, int i) ->
232            { throw new JsonTypeArrException(sr.ja, i, STRING, jv, String.class); };
233    }
234}