001package Torello.Browser.JsonAST;
002
003import Torello.JSON.ReadJSON;
004
005import Torello.Java.Additional.Ret2;
006
007import javax.json.JsonObject;
008
009/**
010 * Extracts the Json Property {@code "type"} from the {@link JsonObject} which defines an
011 * {@link Entity} instance, and converts that {@code String} into an instance of {@link TypeProp}.
012 * This class also extracts, if present, the {@code "type"} property from within an {@code "items"}
013 * {@code JsonObject}.  These (the second) {@code "type"} are used <B STYLE='color:red;'><I>if and
014 * only if</B></I> the first {@code "type"} has a value of {@link TypeProp#ARRAY "array"}, and 
015 * subsequently requires a definition for the Array's Base-Component Class.
016 * 
017 * <BR /><BR />The only values which are ever assigned to the Json {@code "type"} property will 
018 * directly correspond to one of the enum constants listed inside the {@link TypeProp} enum.  
019 * It is of utmost important to remember, that if a {@link PPR} has a "Type" that is actually one 
020 * of the specified types from the spec files (rather than something simple like {@code 'integer'} 
021 * or {@code 'string'}), that {@code PPR} will not even use the Json {@code "type"} property.  
022 * 
023 * <BR /><BR />Instead, the {@code "$ref"} property will contain a "Reference as a String" (which 
024 * will later require linkinig) that gives the name of the class / type of which the {@code PPR}
025 * is a reference.
026 */
027@Torello.JavaDoc.Annotations.StaticFunctional
028@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="CONSTRUCTOR_JDHBI")
029public class Helper$TypeProps 
030{
031    private Helper$TypeProps() { }
032
033    private static final Ret2<TypeProp, TypeProp> EMPTY_RET2 = new Ret2<>(null, null);
034
035    static Ret2<TypeProp, TypeProp> get(final JsonObject jo)
036    {
037        // getString(JsonObject jo, String propertyName, boolean isOptional, boolean throwOnNull)
038        final String typePropStr = ReadJSON.getString(jo, "type", true, true);
039
040
041        // If there is no "type" Json-Property, then there is a zero 0% chance that there is going
042        // to be an "items" Json-Property.  As such, if 'typePropStr' is null, return 2 nulls
043        // immediately.
044
045        if (typePropStr == null) return EMPTY_RET2;
046
047        // Conver the "type" String into an insance of the TypeProp enum....
048        final TypeProp typeProp = TypeProp.valueOf(typePropStr.toUpperCase());
049
050
051        // Similar to before, but ...  Here, if there did happen to be a "type" Json Property, 
052        // unless that "type" equaled the String "array", then there (again) is a zero 0% chance 
053        // that there is going to be an "items" Json-Property.  If it was something other than 
054        // "array", return the first TypeProp enum instance immediately, and null for the items 
055        // TypeProp instance.
056
057        if (typeProp != TypeProp.ARRAY) return new Ret2<>(typeProp, null);
058
059
060        // Here, if this line of code is reached, then the "items" Json Property is not goingt to 
061        // be optional.  This ReadJSON invocation will throw an exception if the "items" property
062        // isn't available inside the input JsonObject / 'jo' instance.
063        // 
064        // getJsonObject(JsonObject, String propertyName, boolean isOptional, boolean throwOnNull)
065
066        final JsonObject arrItemsProp = ReadJSON.getJsonObject(jo, "items", false, true);
067
068
069        // Lastly, now that we have the "items" Json Property, which is actually another / inner
070        // JsonObject, we need to extract the contents of this JsonObject.  This inner JO, which is
071        // being called "arrItemsProp" may have exactly one of two different Json Properties
072        // itself.  They are:
073        // 
074        //      1) "type": "some-type"
075        //      2) "$ref": "some-TypeNode-Name"
076        // 
077        // If the caller of this method is a constructor for a PPR, then this "items" Json-Object
078        // could just as easily be a "$ref" array, as it could be a "type" array.  If the caller of
079        // this method is a TypeNode, it would only be possible for this "items" Json-Object to be 
080        // a 'jo' that contains a "type" property, itself.  TypeNode TCE's may not be declared as 
081        // array's of references.  Only PPR's may have array's of references.
082        // 
083        // In such cases, if the "items" 'jo' isn't an object that has a "type" Json-Property, then
084        // by definition it must have a "$ref" Json-Property instead.  This is where an 'Entity' is
085        // being declared as an array of some other declared type.  If this were Java instead of 
086        // JSON, it would be like declaring an array of some Java-Class, rather than a primitive 
087        // array such as 'int[]' or 'boolean[]'
088        // 
089        // If the Entity is an array of "$ref", then we need to just return null in place of the 
090        // 2nd TypeProp Parameter.  This is going to be done intentionally.  What this actually 
091        // means is that if an "Entity" - which is the Root Object Inheritance Class for all AST
092        // Nodes - is declared as an "array", but the "component class" (Java calls the class about
093        // which an array is declared as the "component" class) is an actual object rather than a 
094        // primitive, then that component class is going to be extracted and computed by another
095        // constructor, elswhere in this package's source code.
096        // 
097        // This is because there is only, single, kind of AST Node that is permitted to declare 
098        // array's of references - PPR Nodes.  If a TCE is declared as an "array", it must be a 
099        // "simple array" - using one of types that are listed in the "TypeProp" enum.
100        // 
101        // *** NOTE: The TypeProp 'enum' is **NEARLY** but not identical to Java-Primitives.
102        // 
103        // 1) First, Java Class 'java.lang.String' is one of the types listed in TypeProp - which
104        //    is not a Java-Primitive, but it is treated like a "Simple Type" - not a
105        //    Reference-Type in this package.  In the JsonAST Package "Reference Types" are types
106        //    which point to ANOTHER DECLARED TYPE FROM THIS VERY JSON-AST TREE!  
107        // 
108        //    For Example: In the "JavaScript API", inside the "RunTime Domain", there is a type 
109        //    called "RunTime.RemoteObject" - **THAT** would be a "$ref" type.
110        //    A PPR whose "type" was "RunTime.RemoteObject[]" would be a reference array
111        //    While a PPR whose Type was "String[]" would be treated like a simple array
112        // 
113        // 2) Second, class "Number" does not directly map to a Java Primitive.  It is unknown
114        //    whether a browser which is connected over the Web-Sockets will switch back and forth
115        //    between "integer" and "float" types.  However, if the specifications JSON File 
116        //    declares a PPR to be a "number" rather than an "integer", such a declaration is 
117        //    treated as if the browser may return either an integer or a real number.
118        // 
119        //    As such, the Java Boxed-Type "Number" is used, which allows for both class
120        //    'java.lang.Integer' and also 'java.lang.Double'.  The Java-HTML 'ReadJSON' package'
121        //    ReadJSON class is good about figuring out which of the two to return.
122        // 
123        // 
124        // getString(JsonObject jo, String propertyName, boolean isOptional, boolean throwOnNull)
125        // PAY CLOSE ATTENTION: 'isOption' ==> TRUE  (won't throw if this Json-Property is missing)
126
127        final String arrType  = ReadJSON.getString(arrItemsProp, "type", true, true);
128
129
130        // If It was missing, just leave it off.  The PPR Construtor will look for a "$ref"
131        // Property instead.  It will even throw there if there also happens to not be a "$ref"
132        // property inside the "items" Json Object either!
133
134        if (arrType == null) return new Ret2<>(typeProp, null);
135
136        // It wasn't null, so there was a "type" property inside the "items" Json Object.
137        final TypeProp arrTypeProp = TypeProp.valueOf(arrType.toUpperCase());
138
139        return new Ret2<>(typeProp, arrTypeProp);
140    }
141
142}