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

import Torello.Java.ReadOnly.ReadOnlyList;
import Torello.Java.UnreachableError;

/**
 * This class generates the "Computed Type as String" for a {@link PPR} instance.
 * <EMBED CLASS='external-html' DATA-FILE-ID=PPR_CTAS>
 */
@Torello.JavaDoc.Annotations.StaticFunctional
@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="LINKER_JDHBI")
public class PPR_CTAS
{
    private PPR_CTAS() { }

    // REMEMBER:
    // 
    //  1) Both TypeNode's and PPR's have a CTAS / CTAB field
    // 
    //  2) TypeNode's CTAS / CTAB can be computed inside their constructors.  They don't need some
    //     complicated "Linking Stage".  TypeNode's either 'degenerate' into a simple Java type
    //     such as 'java.lang.Sting', or they specify their own, predfined, CDP Browser Type.
    // 
    //  3) TypeNode's never default to being some other CDP defined TypeNode within CDP, that would
    //     make zero sense at all !  (NOTE: There is one lone / hold-out special case which I'm 
    //     simple not going to mention here - "ArrayOfString" - but that's all I'll say...)
    // 
    //      i)      Thusly TypeNode's don't have to wait until all of the other TypeNode's have
    //              been constructed to set their values.
    // 
    //      ii)     Thusly their CTAS / CTAB values can be set, instantaneously, inside thier ctors
    // 
    //      III)    Thusly CTAS / CTAB fields inside of 'TypeNode' can be declared final and can 
    //              avoid a complicated "Link Phase" analysis.
    // 
    //  4) PPR's can deflate into simple Java Types.  But they can also deflate into other CDP
    //     defined Types.  Thusly, they have to wait for the entire AST to be built before they can
    //     have values assigned to their CTAS / CTAB fields or their 'reference' & 'referenceArray'
    //     fields.
    // 
    //  PPR's *HAVE TO WAIT* for all TypeNode's to be constructed before they can be linked!

    static void iterateSetCTAS(final API api)
    { for (final Domain d : api.domains) iterateSetCTAS(d); }

    private static void iterateSetCTAS(final Domain d)
    {
        for (final TypeNode type    : d.types)  iterateSetCTAS(type.properties);
        for (final EventNode event  : d.events) iterateSetCTAS(event.parameters);

        for (final CommandNode command : d.commands)
        {
            iterateSetCTAS(command.parameters);
            iterateSetCTAS(command.returns);
        }
    }

    private static void iterateSetCTAS(final ReadOnlyList<PPR> rol)
    {
        if (rol != null)
            for (final PPR ppr : rol)
                ppr.setCTAS(ctas(ppr));
    }


    // This is one of the center-piece methods for the JsonAST package.  This converts all of the
    // fields inside of class PPR into a String that may be used by the Code-Generator package to
    // generate an actual type for whatever Method-Parameter or Class-Field which this PPR instance
    // ultimately represents.
    // 
    // This called a "Center-Piece" becuase the "linking" really is that difficult to explain in
    // my mind.  It took a long time to fully understand what my code was really doing.

    private static String ctas(final PPR ppr)
    {
        final TypeNode REFERENCE        = ppr.reference();
        final TypeNode REFERENCE_ARR    = ppr.referenceArray();

        if (REFERENCE_ARR != null) return REFERENCE_ARR.isReifiedInnerClass
            ? REFERENCE_ARR.CTAS + "[]"
            : ARRAY_OF_STUFFOLA(REFERENCE_ARR.CTAS);

        else if (REFERENCE != null) return REFERENCE.isReifiedInnerClass
            ? REFERENCE.CTAS
            : STUFFOLA(ppr, REFERENCE.CTAS);

        else if (ppr.arrItemsTypeProp != null)
            return ppr.arrItemsTypeProp.arrayCTAS.getSimpleName();

        else if (ppr.typeProp != null) return ppr.optional 
            ? ppr.typeProp.boxedCTAS.getSimpleName()
            : ppr.typeProp.primCTAS.getSimpleName();

        else throw new UnreachableError();
    }


    // I choose to call this "stuffola" for a very precise and scientific reason
    // But I'm not going to tell you that reason, not now, not today.
    // Damn it Jim, I am just a doctor, not a miracle worker!

    private static String STUFFOLA(final PPR ppr, final String ctas)
    {
        switch (ctas) 
        {
            case "int" :        return ppr.optional ? "Integer" : "int";
            case "boolean" :    return ppr.optional ? "Boolean" : "boolean";
        
            default: return ctas;
        }

    }

    private static String ARRAY_OF_STUFFOLA(final String ctas)
    {
        switch (ctas)
        {
            case "JsonValue":   return "JsonValue";
            case "Integer":     return "int[]";
            case "Boolean":     return "boolean[]";
    
            default: return ctas + "[]";
        }
    }
}