001package Torello.Browser;
002
003import static Torello.Java.StrPrint.I4;
004
005import Torello.Java.ReadOnly.ReadOnlyList;
006
007import java.util.Objects;
008import java.util.TreeMap;
009
010import javax.json.JsonObject;
011
012/**
013 * Reflected information / data which has been extracted from one of the nested CDP types declared
014 * inside a generated domain class.
015 * 
016 * <BR /><BR />
017 * A "Nested Type" is any CDP data-class, event-class, or command-return class that is generated as
018 * an inner class of one of the primary browser domain classes.  For example:
019 * 
020 * <BR /><BR />
021 * <B><CODE>{@link Torello.Browser.BrowserAPI.Animation.AnimationEffect}</CODE></B>
022 * 
023 * <BR /><BR />
024 * is a nested type declared inside the {@code Animation} domain class.  Its corresponding
025 * {@code NestedDescriptor} singleton is created and stored inside that type's generated helper
026 * class:
027 * 
028 * <BR /><BR />
029 * <B><CODE><A HREF='BrowserAPI/hilite-files/Animation$$AnimationEffect$$.java.html'>
030 * Animation$$AnimationEffect$$</A></CODE></B>
031 * 
032 * <BR /><BR />
033 * The descriptor stores the field names, CDP type constants, optional-field flags,
034 * experimental-field flags, and the concrete Java {@link Class} represented by the nested type.
035 * This metadata is used by reflection-based tools such as {@link TypeBuilder}, JSON parsers, and
036 * generated helper classes.
037 * 
038 * @param <DOMAIN_NESTED> The concrete nested CDP type described by this descriptor.
039 */
040public class NestedDescriptor<DOMAIN_NESTED extends BaseType<DOMAIN_NESTED>>
041    extends AbstractDescriptor
042    implements java.io.Serializable
043{
044    // ********************************************************************************************
045    // ********************************************************************************************
046    // Fields
047    // ********************************************************************************************
048    // ********************************************************************************************
049
050
051    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
052    protected static final long serialVersionUID = 1L;
053
054    /**
055     * This just keeps a pointer / reference back to the actual {@code java.lang.Class} which is 
056     * described by this "Nested Descriptor."
057     * 
058     * <BR /><BR /><DIV CLASS=JDHint>
059     * In the JDK, it is sometimes stated that "reifying generic types" could conceivably have 
060     * a value to the end user.  The only purpose of this field is to do just that, "reify" the
061     * Type Parameter represented by {@code 'DOMAIN_NESTED'}.
062     * </DIV>
063     */
064    public final Class<DOMAIN_NESTED> baseTypeClass;
065
066    // This package-private field is used by the "TypeBuilder" class's "build()" method
067    transient java.lang.reflect.Constructor<DOMAIN_NESTED> ctor = null;
068
069
070    // ********************************************************************************************
071    // ********************************************************************************************
072    // Constructor & toString
073    // ********************************************************************************************
074    // ********************************************************************************************
075
076
077    /**
078     * This is a public constructor, but it's primarily intended for internal use.
079     * 
080     * <!-- NOTE: Chat-GPT wrote these "Single Line Summaries!"  Pretty nifty... -->
081     * 
082     * @param name The name of the CDP type described by this descriptor.
083     * @param domain The Browser Domain containing the described CDP type.
084     * @param names Parallel list of CDP property names.
085     * @param types Parallel list of {@link CDPTypes CDP Type Constants}.
086     * @param optionals Parallel list indicating which properties are {@code optional}.
087     * @param experimentals Parallel list indicating which properties are {@code experimental}.
088     * @param baseTypeClass The concrete Java {@code Class} represented by this descriptor.
089     */
090    public NestedDescriptor(
091            final Domains               domain,
092            final String                name,
093            final ReadOnlyList<String>  names,
094            final ReadOnlyList<Byte>    types,
095            final ReadOnlyList<Boolean> optionals,
096            final ReadOnlyList<Boolean> experimentals,
097            final Class<DOMAIN_NESTED>  baseTypeClass
098        )
099    {
100        super(name, domain, names, types, optionals, experimentals);
101        Objects.requireNonNull(baseTypeClass, "Constructor parameter 'baseTypeClass' is null");
102        this.baseTypeClass = baseTypeClass;
103    }
104
105    /**
106     * Generates a reasonable {@code String} representation of {@code 'this'} instance.
107     * @return A Java {@code String}
108     */
109    @Override
110    public String toString()
111    {
112        return 
113            "NestedDescriptor:\n" +
114            "{\n" +
115            super.toString() +
116            '\n' +
117            I4 + "baseTypeClass: " + this.baseTypeClass.getCanonicalName() + '\n' +
118            "}\n";
119    }
120
121
122    // ********************************************************************************************
123    // ********************************************************************************************
124    // Package-Private Reflection Methods
125    // ********************************************************************************************
126    // ********************************************************************************************
127
128
129    // Allows the TypeBuilder to verify if a user has passed a valid class
130    Class<?> getClass(final String name, final int index)
131    {
132        final java.lang.reflect.Field field;
133
134        try
135            { field = baseTypeClass.getField(name); }
136
137        catch (NoSuchFieldException | SecurityException e)
138            { throw new Error("Exception retrieving field [" + name + ']', e); }
139
140        if (field == null) throw new Error(
141            "Class " + baseTypeClass.getCanonicalName() + " did not contain a field " +
142            "named: " + name
143        );
144
145        return field.getType();
146    }
147}