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

import Torello.Java.UnreachableError;

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

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

import java.math.BigDecimal;

// NOTE: This is not Rocket-Science.  It just looks really complicated.
// 
// Stuff with "Types" becomes so heinous to look at.  I started this package in
// 2022, and it is now 2025.  The Package Torello.Java.JSON has more testing code than
// literally any of the other packages in this Library.
// 
// I'm still not done testing it.  There is still more that I should do.
// 
// The only purpose of making a "String-Handler" is so that the MAIN-PROCESSING-LOOP
// which is in class "ProcessJsonArr" is short, simple & sweet.  It just calls the handlers that
// are saved inside of the "SettingsRec".  The SettingsRec gets a String-Handler from this class!
// 
// 
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 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 ChooseStringHandler
{
    static <T> ObjIntConsumer<JsonString> useUserParser(
            final SettingsRec<T, ?>     sr,
            final Class<T>              CLASS,
            final ObjIntConsumer<T>     ACCEPTOR,
            final Function<String, T>   userParser,
            final IntConsumer           handlerSPEX
        ) 
    {
        return (final JsonString js, final int i) ->
        {
            try
                { ACCEPTOR.accept(userParser.apply(js.getString()), i); }

            catch (Exception e)
            {
                // 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).

                if (handlerSPEX != null) handlerSPEX.accept(i);
                else throw new JsonStrParseArrException(e, sr.ja, i, js, CLASS);
            }
        };
    }

    static <T> ObjIntConsumer<JsonString> parseString(
            final SettingsRec<T, ?>     sr,
            final Class<T>              CLASS,
            final ObjIntConsumer<T>     ACCEPTOR,
            final IntConsumer           handlerSPEX,
            final IntConsumer           handlerZLS,
            final Predicate<String>     validStrTester,
            final Function<String, T>   defaultParser
        )
    {
        return (final JsonString js, final int i) ->
        {
            String s = js.getString();

            if (s.length() == 0)
            {
                if (handlerZLS != null) handlerZLS.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 throw new JsonStrParseArrException(
                    new IllegalArgumentException("Zero Length String"),
                    sr.ja, i, js, CLASS
                );
            }

            // StringParse.isInteger(s), isLong(String) **AND** s -> true (Double)
            else if (validStrTester.test(s))

                // Integer.parseInt(String), Long.parseLong, Double.parseDouble
                ACCEPTOR.accept(defaultParser.apply(s), i);

            else if (handlerSPEX != null) handlerSPEX.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 throw new JsonStrParseArrException
                (getSPEX(s, defaultParser), sr.ja, i, js, CLASS);
        };
    }

    // Small Internal, static, helper
    private static Exception getSPEX(final String s, final Function<String, ?> converter)
    {
        try
            { converter.apply(s); }

        catch (Exception e)
            { return e; }

        throw new UnreachableError();
    }

    @SuppressWarnings("unchecked")
    static <T> ObjIntConsumer<JsonString> parseStringNUMBER(
            final SettingsRec<T, ?> sr,
            final Class<T>          CLASS,
            final ObjIntConsumer<T> ACCEPTOR,
            final IntConsumer       handlerSPEX,
            final IntConsumer       handlerZLS
        )
    {
        return (final JsonString js, final int i) ->
        {
            String s = js.getString();

            if (s.length() == 0)
            {
                if (handlerZLS != null) handlerZLS.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 throw new JsonStrParseArrException(
                    new IllegalArgumentException("Zero Length String"),
                    sr.ja, i, js, CLASS
                );

                return;
            }

            final BigDecimal bd;

            try
                { bd = new BigDecimal(s); }

            catch (Exception e)
            {
                if (handlerSPEX != null) handlerSPEX.accept(i);

                else throw new JsonStrParseArrException
                    (e, sr.ja, i, js, Number.class);

                return;
            }

            ((ObjIntConsumer<Number>) ACCEPTOR).accept(RJInternal.convertToNumber(bd), i);
        };
    }
}