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
package Torello.Browser.JsonAST;

import Torello.JSON.ReadJSON;

import Torello.Java.Additional.Ret2;

import javax.json.JsonObject;

/**
 * Extracts the Json Property {@code "type"} from the {@link JsonObject} which defines an
 * {@link Entity} instance, and converts that {@code String} into an instance of {@link TypeProp}.
 * This class also extracts, if present, the {@code "type"} property from within an {@code "items"}
 * {@code JsonObject}.  These (the second) {@code "type"} are used <B STYLE='color:red;'><I>if and
 * only if</B></I> the first {@code "type"} has a value of {@link TypeProp#ARRAY "array"}, and 
 * subsequently requires a definition for the Array's Base-Component Class.
 * 
 * <BR /><BR />The only values which are ever assigned to the Json {@code "type"} property will 
 * directly correspond to one of the enum constants listed inside the {@link TypeProp} enum.  
 * It is of utmost important to remember, that if a {@link PPR} has a "Type" that is actually one 
 * of the specified types from the spec files (rather than something simple like {@code 'integer'} 
 * or {@code 'string'}), that {@code PPR} will not even use the Json {@code "type"} property.  
 * 
 * <BR /><BR />Instead, the {@code "$ref"} property will contain a "Reference as a String" (which 
 * will later require linkinig) that gives the name of the class / type of which the {@code PPR}
 * is a reference.
 */
@Torello.JavaDoc.Annotations.StaticFunctional
@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="CONSTRUCTOR_JDHBI")
public class Helper$TypeProps 
{
    private Helper$TypeProps() { }

    private static final Ret2<TypeProp, TypeProp> EMPTY_RET2 = new Ret2<>(null, null);

    static Ret2<TypeProp, TypeProp> get(final JsonObject jo)
    {
        // getString(JsonObject jo, String propertyName, boolean isOptional, boolean throwOnNull)
        final String typePropStr = ReadJSON.getString(jo, "type", true, true);


        // If there is no "type" Json-Property, then there is a zero 0% chance that there is going
        // to be an "items" Json-Property.  As such, if 'typePropStr' is null, return 2 nulls
        // immediately.

        if (typePropStr == null) return EMPTY_RET2;

        // Conver the "type" String into an insance of the TypeProp enum....
        final TypeProp typeProp = TypeProp.valueOf(typePropStr.toUpperCase());


        // Similar to before, but ...  Here, if there did happen to be a "type" Json Property, 
        // unless that "type" equaled the String "array", then there (again) is a zero 0% chance 
        // that there is going to be an "items" Json-Property.  If it was something other than 
        // "array", return the first TypeProp enum instance immediately, and null for the items 
        // TypeProp instance.

        if (typeProp != TypeProp.ARRAY) return new Ret2<>(typeProp, null);


        // Here, if this line of code is reached, then the "items" Json Property is not goingt to 
        // be optional.  This ReadJSON invocation will throw an exception if the "items" property
        // isn't available inside the input JsonObject / 'jo' instance.
        // 
        // getJsonObject(JsonObject, String propertyName, boolean isOptional, boolean throwOnNull)

        final JsonObject arrItemsProp = ReadJSON.getJsonObject(jo, "items", false, true);


        // Lastly, now that we have the "items" Json Property, which is actually another / inner
        // JsonObject, we need to extract the contents of this JsonObject.  This inner JO, which is
        // being called "arrItemsProp" may have exactly one of two different Json Properties
        // itself.  They are:
        // 
        //      1) "type": "some-type"
        //      2) "$ref": "some-TypeNode-Name"
        // 
        // If the caller of this method is a constructor for a PPR, then this "items" Json-Object
        // could just as easily be a "$ref" array, as it could be a "type" array.  If the caller of
        // this method is a TypeNode, it would only be possible for this "items" Json-Object to be 
        // a 'jo' that contains a "type" property, itself.  TypeNode TCE's may not be declared as 
        // array's of references.  Only PPR's may have array's of references.
        // 
        // In such cases, if the "items" 'jo' isn't an object that has a "type" Json-Property, then
        // by definition it must have a "$ref" Json-Property instead.  This is where an 'Entity' is
        // being declared as an array of some other declared type.  If this were Java instead of 
        // JSON, it would be like declaring an array of some Java-Class, rather than a primitive 
        // array such as 'int[]' or 'boolean[]'
        // 
        // If the Entity is an array of "$ref", then we need to just return null in place of the 
        // 2nd TypeProp Parameter.  This is going to be done intentionally.  What this actually 
        // means is that if an "Entity" - which is the Root Object Inheritance Class for all AST
        // Nodes - is declared as an "array", but the "component class" (Java calls the class about
        // which an array is declared as the "component" class) is an actual object rather than a 
        // primitive, then that component class is going to be extracted and computed by another
        // constructor, elswhere in this package's source code.
        // 
        // This is because there is only, single, kind of AST Node that is permitted to declare 
        // array's of references - PPR Nodes.  If a TCE is declared as an "array", it must be a 
        // "simple array" - using one of types that are listed in the "TypeProp" enum.
        // 
        // *** NOTE: The TypeProp 'enum' is **NEARLY** but not identical to Java-Primitives.
        // 
        // 1) First, Java Class 'java.lang.String' is one of the types listed in TypeProp - which
        //    is not a Java-Primitive, but it is treated like a "Simple Type" - not a
        //    Reference-Type in this package.  In the JsonAST Package "Reference Types" are types
        //    which point to ANOTHER DECLARED TYPE FROM THIS VERY JSON-AST TREE!  
        // 
        //    For Example: In the "JavaScript API", inside the "RunTime Domain", there is a type 
        //    called "RunTime.RemoteObject" - **THAT** would be a "$ref" type.
        //    A PPR whose "type" was "RunTime.RemoteObject[]" would be a reference array
        //    While a PPR whose Type was "String[]" would be treated like a simple array
        // 
        // 2) Second, class "Number" does not directly map to a Java Primitive.  It is unknown
        //    whether a browser which is connected over the Web-Sockets will switch back and forth
        //    between "integer" and "float" types.  However, if the specifications JSON File 
        //    declares a PPR to be a "number" rather than an "integer", such a declaration is 
        //    treated as if the browser may return either an integer or a real number.
        // 
        //    As such, the Java Boxed-Type "Number" is used, which allows for both class
        //    'java.lang.Integer' and also 'java.lang.Double'.  The Java-HTML 'ReadJSON' package'
        //    ReadJSON class is good about figuring out which of the two to return.
        // 
        // 
        // getString(JsonObject jo, String propertyName, boolean isOptional, boolean throwOnNull)
        // PAY CLOSE ATTENTION: 'isOption' ==> TRUE  (won't throw if this Json-Property is missing)

        final String arrType  = ReadJSON.getString(arrItemsProp, "type", true, true);


        // If It was missing, just leave it off.  The PPR Construtor will look for a "$ref"
        // Property instead.  It will even throw there if there also happens to not be a "$ref"
        // property inside the "items" Json Object either!

        if (arrType == null) return new Ret2<>(typeProp, null);

        // It wasn't null, so there was a "type" property inside the "items" Json Object.
        final TypeProp arrTypeProp = TypeProp.valueOf(arrType.toUpperCase());

        return new Ret2<>(typeProp, arrTypeProp);
    }

}