001package Torello.JSON;
002
003import Torello.Java.UnreachableError;
004
005import java.util.function.ObjIntConsumer;
006import java.util.function.IntConsumer;
007import java.util.function.Predicate;
008import java.util.function.Function;
009
010import javax.json.JsonValue;
011import javax.json.JsonString;
012
013import java.math.BigDecimal;
014
015
016// NOTE: This is not Rocket-Science.  It just looks really complicated.
017// 
018// Stuff with "Types" becomes so heinous to look at.  I started this package in
019// 2022, and it is now 2025.  The Package Torello.JSON has more testing code than
020// literally any of the other packages in this Library.
021// 
022// I'm still not done testing it.  There is still more that I should do.
023// 
024// The only purpose of making a "String-Handler" is so that the MAIN-PROCESSING-LOOP
025// which is in class "ProcessJsonArr" is short, simple & sweet.  It just calls the handlers that
026// are saved inside of the "SettingsRec".  The SettingsRec gets a String-Handler from this class!
027// 
028// 
029// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
030// The 'ja' instance declared in class "SettingsRec" **IS NOT** declared final.  It can be reset !
031// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
032// 
033// IMPORTANT NOTE: The 'ja' that is passed to the Functional-Interface Implementatons which are 
034// constructed in this method is "de-referenced" from the SettingsRec -- It **IS NOT** passed as
035// a parameter to this method.  If it **WERE NOT** retrieved from the 'SettingsRec', then 'sr'
036// instance, then the 'ja' that would be used would be permanently-solidified to the 'ja' 
037// referenced that were passed right at the beginning, upon construction of the SettingsRec
038// instance.
039
040@Torello.JavaDoc.Annotations.StaticFunctional
041public class ChooseStringHandler
042{
043    private ChooseStringHandler() {}
044
045
046    static <T> ObjIntConsumer<JsonString> useUserParser(
047            final SettingsRec<T, ?>     sr,
048            final Class<T>              CLASS,
049            final ACCEPTOR<T>           acceptor,
050            final Function<String, T>   userParser,
051            final IntConsumer           handlerSPEX
052        ) 
053    {
054        return (final JsonString js, final int i) ->
055        {
056            try
057                { acceptor.accept(userParser.apply(js.getString()), i); }
058
059            catch (Exception e)
060            {
061                // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
062                // versus 'ja' (being passed as a parameter to this method).
063
064                if (handlerSPEX != null) handlerSPEX.accept(i);
065                else throw new JsonStrParseArrException(e, sr.ja, i, js, CLASS);
066            }
067        };
068    }
069
070    static <T> ObjIntConsumer<JsonString> parseString(
071            final SettingsRec<T, ?>     sr,
072            final Class<T>              CLASS,
073            final ACCEPTOR<T>           acceptor,
074            final IntConsumer           handlerSPEX,
075            final IntConsumer           handlerZLS,
076            final Predicate<String>     validStrTester,
077            final Function<String, T>   defaultParser
078        )
079    {
080        return (final JsonString js, final int i) ->
081        {
082            String s = js.getString();
083
084            if (s.length() == 0)
085            {
086                if (handlerZLS != null) handlerZLS.accept(i);
087
088
089                // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
090                // versus 'ja' (being passed as a parameter to this method).
091
092                else throw new JsonStrParseArrException(
093                    new IllegalArgumentException("Zero Length String"),
094                    sr.ja, i, js, CLASS
095                );
096            }
097
098            // StringParse.isInteger(s), isLong(String) **AND** s -> true (Double)
099            else if (validStrTester.test(s))
100
101                // Integer.parseInt(String), Long.parseLong, Double.parseDouble
102                acceptor.accept(defaultParser.apply(s), i);
103
104            else if (handlerSPEX != null) handlerSPEX.accept(i);
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 throw new JsonStrParseArrException
111                (getSPEX(s, defaultParser), sr.ja, i, js, CLASS);
112        };
113    }
114
115    // Small Internal, static, helper
116    private static Exception getSPEX(final String s, final Function<String, ?> converter)
117    {
118        try
119            { converter.apply(s); }
120
121        catch (Exception e)
122            { return e; }
123
124        throw new UnreachableError();
125    }
126
127    @SuppressWarnings("unchecked")
128    static <T> ObjIntConsumer<JsonString> parseStringNUMBER(
129            final SettingsRec<T, ?> sr,
130            final Class<T>          CLASS,
131            final ACCEPTOR<T>       acceptor,
132            final IntConsumer       handlerSPEX,
133            final IntConsumer       handlerZLS
134        )
135    {
136        return (final JsonString js, final int i) ->
137        {
138            String s = js.getString();
139
140            if (s.length() == 0)
141            {
142                if (handlerZLS != null) handlerZLS.accept(i);
143
144
145                // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja'
146                // versus 'ja' (being passed as a parameter to this method).
147
148                else throw new JsonStrParseArrException(
149                    new IllegalArgumentException("Zero Length String"),
150                    sr.ja, i, js, CLASS
151                );
152
153                return;
154            }
155
156            final BigDecimal bd;
157
158            try
159                { bd = new BigDecimal(s); }
160
161            catch (Exception e)
162            {
163                if (handlerSPEX != null) handlerSPEX.accept(i);
164
165                else throw new JsonStrParseArrException
166                    (e, sr.ja, i, js, Number.class);
167
168                return;
169            }
170
171            // ((ObjIntConsumer<Number>) ACCEPTOR).accept(ReadNumberJSON.convertToNumber(bd), i);
172            ((ACCEPTOR<Number>) acceptor).accept(ReadNumberJSON.convertToNumber(bd), i);
173        };
174    }
175}