001package Torello.Browser.JsonAST;
002
003import Torello.JavaDoc.Annotations.LinkJavaSource;
004import Torello.JavaDoc.Annotations.JDHeaderBackgroundImg;
005
006import Torello.Java.ReadOnly.ReadOnlyList;
007import Torello.Java.ReadOnly.ReadOnlyMap;
008import Torello.Java.ReadOnly.ReadOnlySet;
009import Torello.Java.ReadOnly.ReadOnlyTreeSet;
010
011import Torello.Browser.CDPTypes;
012
013import javax.json.JsonObject;
014import java.io.IOException;
015import java.util.Iterator;
016import java.util.Objects;
017
018/**
019 * An Java Object used within AST to symbolize or encapsulate the data present in any of the 
020 * {@link JsonObject JsonObject's} found within a {@link Domain Domain's} {@code "types"} array.
021 * 
022 * <EMBED CLASS='external-html' DATA-FILE-ID=AST_TREES>
023 */
024@JDHeaderBackgroundImg(EmbedTagFileID="AST_NODES_JDHBI")
025public class TypeNode extends TCE implements java.io.Serializable, Iterable<PPR>
026{
027    // ********************************************************************************************
028    // ********************************************************************************************
029    // STATIC FINAL FIELDS
030    // ********************************************************************************************
031    // ********************************************************************************************
032
033
034    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
035    protected static final long serialVersionUID = 1;
036
037    /**
038     * The list of additional {@link JsonObject} properties that the parser should expect when
039     * parsing {@code TypeNode} objects from the JSON CDP specification files.
040     */
041    protected static final ReadOnlySet<String> TYPE_JSON_PROPERTIES_SET =
042        new ReadOnlyTreeSet<>(String::compareTo, "id", "properties");
043
044
045    // ********************************************************************************************
046    // ********************************************************************************************
047    // Constant & Final Instance-Fields (Set by the Constructor)
048    // ********************************************************************************************
049    // ********************************************************************************************
050
051
052    /** 
053     * Collection of PPR (Property) instances that will be materialized as Java class fields. 
054     * <EMBED CLASS='external-html' DATA-FILE-ID=TypeNode.properties>
055     */
056    public final ReadOnlyList<PPR> properties;
057
058    /** 
059     * Flag indicating whether this TypeNode represents a reified inner class in the CDP model. 
060     * <EMBED CLASS='external-html' DATA-FILE-ID=TypeNode.isReifiedInnerClass>
061     */
062    public final boolean isReifiedInnerClass;
063
064    /** 
065     * <B>{@code CTAS:} Computed Type as String:</B> is a field which summarizing this TypeNode’s
066     * resolved Java Type. 
067     * 
068     * <EMBED CLASS='external-html' DATA-FILE-ID=TypeNode.CTAS>
069     * 
070     * @see CTAB
071     */
072    public final String CTAS;
073
074    /** 
075     * <B>{@code CTAB:} Computed Type as Byte:</B> identical to {@link #CTAS}; however the 
076     * information is encoded as a {@code 'byte'} primitive as per the list of types exposed in
077     * class {@link CDPTypes}.
078     * 
079     * @see CTAS
080     * @see CDPTypes 
081     * @see CDPTypes#ctasToByte(String)
082     */
083    public final byte CTAB;
084
085
086    // ********************************************************************************************
087    // ********************************************************************************************
088    // Constructor
089    // ********************************************************************************************
090    // ********************************************************************************************
091
092
093    // Constructs a class that represents a Java-Script 'type', 'command' or 'event'
094    TypeNode(
095            // The domain to which this 'type', 'command' or 'event' belongs
096            final Domain parent,
097
098            // The JSON Object representation of this 'TCE'
099            final JsonObject jo,
100
101            // The JSON Array index from which this JSON Object was retrieved.
102            final int index
103        )
104    {
105        super(
106            parent,
107            jo,
108            WhichTCE.Type,
109            TYPE_JSON_PROPERTIES_SET,
110            index
111        );
112
113        this.properties             = Helper$GetPPRLists.get(this, jo, WhichPPR.Property);
114        this.isReifiedInnerClass    = (this.properties != null);
115
116
117        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
118        // Simple Error Check, Part 1
119        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
120
121        // TypeNode → **MUST** have a "type" JsonProperty ==> 100% pass / TRUE / invariant
122        if (this.typeProp == null)
123            verifyThrow("TypeNode (TCE) does not declare a \"type\" Json property.");
124
125
126        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
127        // CTAS: Computed Type As String
128        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
129
130        if (this.isReifiedInnerClass)
131            this.CTAS = this.ownerDomain.name + '.' + this.name;
132
133        else if (this.arrItemsTypeProp != null)
134            this.CTAS = this.arrItemsTypeProp.primCTAS.getSimpleName();
135
136        else if (this.typeProp == TypeProp.ARRAY)
137        {
138            // DOMSnapShot.ArrayOfStrings ==> int[]
139            // Target.TargetFilter  ==>  FilterEntry[]
140
141            if (SPECIAL_CASES$TypeNode.ARRAY_OF_REF_TYPES.containsKey(this.name))
142                this.CTAS = SPECIAL_CASES$TypeNode.ARRAY_OF_REF_TYPES.get(this.name);
143
144            else throw (ASTError) this.verifyThrow(
145                "Impossible: A TypeNode declared a \"type\": \"array\", but the \"items\" " +
146                "property does not have its own \"type\" property declared."
147            );
148        }
149
150        else this.CTAS = this.typeProp.primCTAS.getSimpleName();
151
152        // CTAB: Computed Type As Byte - same information as CTAS, but stored as a byte primitive
153        this.CTAB = CDPTypes.ctasToByte(this.CTAS);
154
155
156        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
157        // Simple Error Check, Part 2
158        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
159        // 
160        // Logical Rule: If (type == OBJECT) → (properties must be non-null and non-empty)
161        // 100% Pass / Success Rate 
162        // Case 1: Modus Tollens
163        //
164        // Here: properties exist ⇒ Therefore, type must be OBJECT.
165        // This block catches violations where type ≠ OBJECT but properties are still present.
166
167        if ((this.properties != null) && (this.typeProp != TypeProp.OBJECT))
168            verifyThrow("TypeNode.typeProp != OBJECT, but typeNode.properties is non-null.");
169
170
171        // 99.99% Pass / Success Rate
172        // Case 2: Modus Ponens
173        // 
174        // If (type == OBJECT) → (properties exist)
175        // Here: type == OBJECT ⇒ Therefore, properties must exist.
176        // This block catches violations where type == OBJECT but no properties are defined.
177        // 
178        // There were exactly 2 outliers with this one. (out of 1,444 invocations of this method)
179        // TCE: (MemoryDumpConfig), API: [BrowserAPI],  Domain: [Tracing],  WhichTCE: "Type"
180        // TCE: (Headers),          API: [BrowserAPI],  Domain: [Network],  WhichTCE: "Type"
181
182        if ((this.typeProp == TypeProp.OBJECT) && (this.properties == null))
183            if (! SPECIAL_CASES$TypeNode.OBJECT_WITHOUT_PROPERTIES_OK.contains(this.name))
184                verifyThrow("TypeNode.typeProp == OBJECT, but typeNodeproperties is null");
185    }
186
187
188    // ********************************************************************************************
189    // ********************************************************************************************
190    // toString
191    // ********************************************************************************************
192    // ********************************************************************************************
193
194
195    /**
196     * Returns an {@code Iterator} that iterates the contents of the {@link #properties} list.
197     * 
198     * @see #properties
199     * @see Torello.Java.Additional.RemoveUnsupportedIterator
200     */
201    public Iterator<PPR> iterator()
202    { return this.properties.iterator(); }
203
204    /** Returns a {@code String} representation of {@code 'this'} instance. */
205    @LinkJavaSource(handle="StringTCE")
206    public String toString()
207    { return StringTCE.get(this); }
208}