001package Torello.JSON;
002
003import Torello.Java.StringParse;
004
005import java.lang.reflect.Array;
006
007import javax.json.JsonArray;
008import javax.json.JsonValue;
009
010import java.util.Arrays;
011import java.util.Objects;
012
013import static javax.json.JsonValue.ValueType.*;
014
015@Torello.JavaDoc.Annotations.StaticFunctional
016public class ProcessMultiDimJsonArray
017{
018    private ProcessMultiDimJsonArray() { }
019
020    /**
021     * This class is invoked by the class {@link RJArrDimN}
022     * 
023     * @param <BASIC_TYPE> The "Component Type" of the Output-Array.
024     * 
025     * @param <STREAM_TYPE> The "Intermediate Stream Type", which is present before the conversion
026     * to an Array.
027     * 
028     * @param <RETURN_ARR_TYPE> The actual Return-Type of the method.  This must be an Array-Class,
029     * such as {@code int[][].class} or (in the case of Boxed-Type Arrays) {@code Integer[][]}.
030     * 
031     * @param ja Any instance of {@link JsonArray}.  The contents sof this array should match the 
032     * dimensionality of the expected Output-Array Type, or an exception will likelyy throw.
033     * 
034     * @param rec An instance of {@link SettingsRec} that's been configured to return a 
035     * multi-dimensional array.
036     * 
037     * @param retArrClass The class of the return array.
038     * @return An instance of {@code 'retArrClass'}
039     */
040    public static <BASIC_TYPE, STREAM_TYPE, RETURN_ARR_TYPE> RETURN_ARR_TYPE jsonArrayToJava(
041            final JsonArray                             ja,
042            final SettingsRec<BASIC_TYPE, STREAM_TYPE>  rec,
043            final Class<RETURN_ARR_TYPE>                retArrClass
044        )
045    {
046        CHECK_ARRAY_CLASS(retArrClass, rec.CLASS);
047        return jsonArrayToJava_INTERNAL(ja, rec, retArrClass);
048    }
049
050    @SuppressWarnings("unchecked")
051    private static <BASIC_TYPE, STREAM_TYPE, RETURN_ARR_TYPE> RETURN_ARR_TYPE
052        jsonArrayToJava_INTERNAL(
053            final JsonArray                             ja,
054            final SettingsRec<BASIC_TYPE, STREAM_TYPE>  rec,
055            final Class<RETURN_ARR_TYPE>                retArrClass
056        )
057    {
058        /*
059        System.out.println(
060            "TOP-OF-METHOD-PART INTERIM PRINTING:\n" +
061            "retArrClass.getSimpleName():       " + retArrClass.getSimpleName() + '\n' +
062            "ja.toString():                     " + ja.toString()
063        );
064        */
065
066        // If this is requesting a one-dimensional array, get it using the 1D-Generator,
067        // and simply return that array.  This requires a cast because there is no way to prove
068        // to the Java-Compiler that <T> is equal to any return-value at all.
069        //
070        // Remember that this is only guaranteed (it works!) because the helper methods are all
071        // protected or private, and it has been guaranteed through rigorous testing, and
072        // preventing the user from playing with it!
073
074        if (StringParse.countCharacters(retArrClass.getSimpleName(), '[') == 1)
075            return (RETURN_ARR_TYPE) rec.array1DGenerator.apply(ja);
076
077
078        // Otherwise, this is not a single-dimension (1D) array.  Instead, the JsonArray needs
079        // to be iterated, and this method called, recursively, on each of the sub-arrays.
080        //
081        // NOTE: 'compClass' will also be an array, but with one fewer dimensions
082
083        final Class<?>  componentClass  = retArrClass.getComponentType();
084        final int       SIZE            = ja.size();
085
086
087        // This generates an instance of the "Array Component Type".  All that means is that this
088        // new array has one fewer set of brackets.  int[][] would become int[]
089
090        final RETURN_ARR_TYPE retArr = (RETURN_ARR_TYPE) Array.newInstance(componentClass, SIZE);
091
092        JsonValue jv = null;
093
094        for (int i=0; i < SIZE; i++)
095
096            switch ((jv = ja.get(i)).getValueType())
097            {
098                // javax.json.JsonValue.ValueType.NULL
099                case NULL: Array.set(retArr, i, null); break;
100
101                // javax.json.JsonValue.ValueType.ARRAY (JsonArray)
102                case ARRAY:
103
104                    final Object newArr =
105                        jsonArrayToJava_INTERNAL((JsonArray) jv, rec, componentClass);
106
107                    /*
108                    // assign these variables using some kind of "if-then-else" and "toString"
109                    // In order to use java.util.Arrays.toString(), you will need to actual type of
110                    // othese objects, and those Parameterized Types are not easy to use with
111                    // java.util.Arrays
112
113                    final String RET_ARR_STR, NEW_ARR_STR;
114
115                    System.out.println(
116                        "retArrClass: " + retArrClass.getSimpleName()       + '\n' +
117                        "retArr:      " + RET_ARR_STR                       + '\n' +
118                        "compClass:   " + componentClass.getSimpleName()    + '\n' +
119                        "newArr:      " + NEW_ARR_STR                       + '\n' +
120                        "i:           " + i                                 + '\n' +
121                        "SIZE:        " + SIZE                              + '\n' +
122                        "jv:          " + jv.toString()                     + '\n'
123                    );
124                    */
125
126                    Array.set(retArr, i, newArr);
127
128                    break;
129
130                // javax.json.JsonValue.ValueType.TRUE, FALSE, NUMBER, STRING, OBJECT
131                default:
132
133                    if (rec.IN_NSAT)        Array.set(retArr, i, null);
134                    else if (rec.S_NSAT)    continue;
135                    else throw new JsonTypeArrException(ja, i, ARRAY, jv, retArrClass);
136            }
137
138        return retArr;
139    }
140
141
142
143    // ********************************************************************************************
144    // ********************************************************************************************
145    // One Helper
146    // ********************************************************************************************
147    // ********************************************************************************************
148
149
150    /**
151     * Check user input, and throws exceptions if the array-class has not been properly
152     * chosen.
153     * 
154     * @param retArrClass This must be a primitive-array class, possibly of multiple dimensions
155     * 
156     * @param expectedRootClass The expected "root class".  For {@code int[][].class}, the root
157     * class would be {@code int.class}.
158     * 
159     * @return Parameter {@code retArrClass} is the return value of this checker method
160     * 
161     * @throws IllegalArgumentExcetion If parameter retArrClass:
162     * If calling retArrClass.isArray() returns FALSE
163     * If the root-array type is not the appropriate type for the method that was called
164     */
165    protected static <T> Class<T> CHECK_ARRAY_CLASS(
166            final Class<T> retArrClass,
167            final Class<?> expectedRootClass
168        )
169    {
170        Objects.requireNonNull(retArrClass, "Return-Array Type, Parameter 'retArrClass' is null");
171
172        if (! retArrClass.isArray()) throw new IllegalArgumentException(
173            "The class you have passed to parameter 'retArrClass' " +
174            "[" + retArrClass.getSimpleName() + "], is not an array"
175        );
176
177        Class<?> componentClass = retArrClass.getComponentType();
178
179        while (componentClass.isArray()) componentClass = componentClass.getComponentType();
180
181        if (! expectedRootClass.equals(componentClass)) throw new IllegalArgumentException(
182            "The class you have passed to parameter 'retArrClass' " +
183            "[" + retArrClass.getSimpleName() + "], is not a(n) " +
184            expectedRootClass.getSimpleName() + "-array."
185        );
186
187        return retArrClass;
188    }
189}