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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
package Torello.HTML.Tools.JavaDoc;

import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
import com.github.javaparser.ast.body.AnnotationMemberDeclaration;

import static Torello.Java.Shell.C.*;
import static Torello.HTML.Tools.JavaDoc.PF.*;

import Torello.Java.*;

import java.util.Optional;
import java.util.function.Consumer;

/**
 * <B STYLE='color:darkred;'>Java Parser Bridge:</B>
 * 
 * Holds all information extracted from <CODE>'&#46;java'</CODE> Annotation
 * (<CODE>&#64;interface</CODE>) Source Files about all Elements identified in that file.
 * 
 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_GET_INST>
 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_AELEM>
 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
 */
@JDHeaderBackgroundImg(EmbedTagFileID={"ANNOTATION_ELEM", "REFLECTION_EXTENSION"})
public class AnnotationElem
    extends Declaration
    implements java.io.Serializable, Comparable<AnnotationElem>, Cloneable
{
    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUID"> */
    public static final long serialVersionUID = 1;

    /**
     * An Annotation-Element may only assume one of several types, as per the Java Sun / Oracle
     * Documentation.  The type must be one of the following, or a compile-time error occurs:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * <LI>a primitive type</LI>
     * <LI>String</LI>
     * <LI>Class or an invocation of Class</LI>
     * <LI>An enum type</LI>
     * <LI>An annotation type</LI>
     * <LI>An (1 dimensional) array type whose component type is one of the preceding types</LI>
     * </UL>
     */
    public final String type;

    /**
     * <BR /><BR /><B STYLE='color:red;'>JOW: Just One Word</B>
     * 
     * <BR /><BR />The <B STYLE='color:red'>Just One Word</B> convention in the upgrader tool 
     * elminates package-name information from type-{@code String's}.
     */
    public final String typeJOW;

    /**
     * The default value assigned to this element.  
     * This may be null if there is no assigned default value.
     */
    public final String defaultValue;


    // ********************************************************************************************
    // ********************************************************************************************
    // Java Parser Reference-Hook
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JP_HOOK_FLD>
     * 
     * If a user decides to make use of the Java-Parser {@code AnnotationMemberDeclaration}
     * instance that was used to build this {@code AnnotationEleme}, it may be retrieved from this
     * {@code transient} field.
     */
    public final transient AnnotationMemberDeclaration annotationMemberDeclaration;


    // ********************************************************************************************
    // ********************************************************************************************
    // Constructors
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Instantiates a {@code AnnotationElem}, and peels out the {@code String's} from a JavaParser
     * {@code AnnotationMemberDeclaration}
     * 
     * <BR /><BR /><B>EXCEPTIONS NOTE:</B> The underlying parser code can throw exceptions, and the
     * exception chain, and exception tree in the package is quite dense.  Suffice it to say, they
     * are all unchecked exceptions.
     * 
     * @param amd This can be retrieved in any number of ways from the JavaParser package.  The
     * instantiation process will convert a Java-Parser from of an
     * {@code AnnotationMemberDeclaration}, <B><I>into this Bridge form
     * {@code class AnnotationElem}</I></B>.
     * 
     * <BR /><BR />Yes, this is redundant, but that's what a bridge is - a wrapper class to make
     * the programmer's life easier. All the salient information a programmer would need when
     * improving JavaDoc Documentation HTML Files is easily and simply encapsulated as lists of
     * {@code String's} in the {@code class AnnotationElem}.
     */
    public AnnotationElem(AnnotationMemberDeclaration amd)
    {
        super(
            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
            // Declaration-Constructor Parameters
            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

            amd.getAnnotations(),       // annotations
            amd.getModifiers(),         // modifiers
            amd.getNameAsString(),      // name

            // Currently, the preferred way to retrieve the "signature"
            LexicalPreservingPrinter.print(LexicalPreservingPrinter.setup(amd)),

            amd.getJavadocComment(),    // JavaDoc Comment
            Entity.ANNOTATION_ELEM,
            amd.getBegin()              //  The Signature Line-Number (Position)
        );

        // Just gets the 'type' of the Element
        // For instance: Excuse[] Excuses, would return 'Excuse[]'

        this.type = amd.getType().toString().trim();

        // NOTE: There are only four allowable types in the first place:
        // Any 'Enum', a 'String', a boolean, and an int.  There is simply no need to use the
        // full-path full-package type-string. (or any array of these types)

        this.typeJOW = StringParse.typeToJavaIdentifier(this.type);

        // If there is a default-value for this annotation, retrieve it
        Optional<Expression> oEx = amd.getDefaultValue();

        this.defaultValue = oEx.isPresent()
            ? LexicalPreservingPrinter.print(LexicalPreservingPrinter.setup(oEx.get())).trim()
            : null;

        // Save the Java Parser reference in a transiet field
        this.annotationMemberDeclaration = amd;
    }


    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Private Constructor, Used by the clone() Method
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

    private AnnotationElem(AnnotationElem other)
    {
        super(other);

        // 'AnnotationElem' specific fields
        this.type                           = other.type;
        this.typeJOW                        = other.typeJOW;
        this.defaultValue                   = other.defaultValue;
        this.annotationMemberDeclaration    = other.annotationMemberDeclaration;
    }


    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    // Used Internally by 'SummaryHTMLFile'
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    //
    // Ensures that the Version with longer type-information strings is used.
    // Java Doc often uses longer type strings

    AnnotationElem(AnnotationElem aeFromJavaParser, String jdTypeStr)
    {
        super(aeFromJavaParser);

        // 'AnnotationElem' specific fields
        this.type                           = jdTypeStr;
        this.typeJOW                        = aeFromJavaParser.typeJOW;
        this.defaultValue                   = aeFromJavaParser.defaultValue;
        this.annotationMemberDeclaration    = aeFromJavaParser.annotationMemberDeclaration;
    }



    // ********************************************************************************************
    // ********************************************************************************************
    // toString(...)
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Generates a {@code String} of this {@code Annotation Element}, with all information included.
     * 
     * @return A printable string of this {@code AnnotationElem}.
     * 
     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
     * @see #toString(int)
     */
    public String toString()
    {
        String def = (defaultValue != null)
            ? ("Default:      [" + StringParse.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
                "]\n") 
            : "";
    
        return
            "Name:         [" + name + "]\n" +
            "Declaration:  [" + StringParse.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
            "Type:         [" + typeJOW + "]\n" +
            "Modifiers:    [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
            def +
            "Line Numbers: [sig=" + signatureLineNumber + ", jdStart=" + jdStartLineNumber +
                                    ", jdEnd=" + jdEndLineNumber + "]";
    }

    /**
     * Generates a {@code String} of this {@code Annotation Element}, with all information
     * included. This will also included any content requested by the {@code 'flags'} parameter.
     * For this class ({@code class AnnotationElem}), the only additional information printed by
     * this {@code 'toString'} method is the Java-Doc Comment {@code String}.
     * 
     * <BR /><BR />This {@code String} may also have UNIX color codes added.
     * 
     * @param flags These are the {@code toString(...)} flags from class {@code PF}
     * ("Print Flags"). View available flags listed in class {@link PF}.
     * 
     * @return A printable {@code String} of this {@code AnnotationElem}.
     * 
     * @see PF
     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
     * @see #toString()
     */
    public String toString(int flags)
    {
        boolean color = (flags & UNIX_COLORS) > 0;

        return
            printedName("Element", 14, color) + 
            printedDeclaration(14, color) +
            "Type-JOW:     [" + typeJOW + "]\n" + 
            printedModifiers(14) +
            printedLineNumbers(14, color) +

            // These are optional, they adds a '\n' AT THE BEGINNING if they are included
            printedDefault(color) +
            printedComments(14, color, (flags & JAVADOC_COMMENTS) > 0);
    }

    private String printedDefault(boolean color)
    {
        // They need to abbreviate, seems extremely "unlikely" - but just in case...
        return (defaultValue == null)
            ? ""
            :  "\nDefault:      [" + (color ? BGREEN : "") +
                StringParse.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
                (color ? RESET : "") + "]";
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Clone, CompareTo & Equals Stuff
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Java's {@code interface Cloneable} requirements.  This instantiates a new
     * {@code AnnotationElem} with identical fields.
     * 
     * @return A new {@code AnnotationElem} whose internal fields are identical to this one.  A
     * deep copy on all internal arrays is performed.  New arrays are instantiated.
     */
    public AnnotationElem clone()
    { return new AnnotationElem(this); }

    /**
     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
     * using the two elements' {@code 'name'} field.
     * 
     * @param ae Any other {@code AnnotationElem} to be compared to {@code 'this' AnnotationElem}
     * 
     * @return An integer that fulfills Java's
     * {@code interface Comparable<AnnotationElem> public boolean compareTo(AnnotationElem ae)}
     * method requirements.
     */
    public int compareTo(AnnotationElem ae)
    { return (this == ae) ? 0 : this.name.compareTo(ae.name); }

    /**
     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
     * other)} method.  This version of equals merely compares the name of the element defined.
     * The presumption here is that the definition of an 'element' only has meaning - <I>at all</I>
     * - inside the context of an {@code Annotation} where that element has been defined.  Since
     * inside any {@code '.java'} {@code Annotation}, there may only be one element with a given
     * name, this method shall return <B>TRUE</B> whenever the element being compared also has the
     * same name.
     * 
     * @param other This may be any other {@code Annotation-Element}.  It is <I><B>strongly
     * suggested</B></I> that {@code 'other'} be an {@code element} defined in the same
     * {@code '.java'} source-code file as {@code 'this'} element.
     * 
     * @return This method returns <B>TRUE</B> when {@code 'this'} instance of
     * {@code AnnotationElem} has the same {@code 'name'} as the name of input-parameter
     * {@code 'other'}
     */
    public boolean equals(AnnotationElem other)
    { return this.name.equals(other.name); }
}