001package Torello.HTML.Tools.JavaDoc;
002
003import com.github.javaparser.ast.NodeList;
004import com.github.javaparser.ast.Modifier;
005import com.github.javaparser.ast.expr.Expression;
006import com.github.javaparser.ast.expr.AnnotationExpr;
007import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
008import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
009
010import static Torello.Java.Shell.C.*;
011import static Torello.HTML.Tools.JavaDoc.PF.*;
012
013import Torello.Java.*;
014
015import java.util.Optional;
016import java.util.function.Consumer;
017
018/**
019 * <B STYLE='color:darkred;'>Java Parser Bridge:</B>
020 * 
021 * Holds all information extracted from <CODE>'&#46;java'</CODE> Annotation
022 * (<CODE>&#64;interface</CODE>) Source Files about all Elements identified in that file.
023 * 
024 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_GET_INST>
025 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_AELEM>
026 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
027 */
028@JDHeaderBackgroundImg(EmbedTagFileID={"ANNOTATION_ELEM", "REFLECTION_EXTENSION"})
029public class AnnotationElem
030    extends Declaration
031    implements java.io.Serializable, Comparable<AnnotationElem>, Cloneable
032{
033    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUID"> */
034    public static final long serialVersionUID = 1;
035
036    /**
037     * An Annotation-Element may only assume one of several types, as per the Java Sun / Oracle
038     * Documentation.  The type must be one of the following, or a compile-time error occurs:
039     * 
040     * <BR /><BR /><UL CLASS=JDUL>
041     * <LI>a primitive type</LI>
042     * <LI>String</LI>
043     * <LI>Class or an invocation of Class</LI>
044     * <LI>An enum type</LI>
045     * <LI>An annotation type</LI>
046     * <LI>An (1 dimensional) array type whose component type is one of the preceding types</LI>
047     * </UL>
048     */
049    public final String type;
050
051    /**
052     * <BR /><BR /><B STYLE='color:red;'>JOW: Just One Word</B>
053     * 
054     * <BR /><BR />The <B STYLE='color:red'>Just One Word</B> convention in the upgrader tool 
055     * elminates package-name information from type-{@code String's}.
056     */
057    public final String typeJOW;
058
059    /**
060     * The default value assigned to this element.  
061     * This may be null if there is no assigned default value.
062     */
063    public final String defaultValue;
064
065
066    // ********************************************************************************************
067    // ********************************************************************************************
068    // Java Parser Reference-Hook
069    // ********************************************************************************************
070    // ********************************************************************************************
071
072
073    /**
074     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JP_HOOK_FLD>
075     * 
076     * If a user decides to make use of the Java-Parser {@code AnnotationMemberDeclaration}
077     * instance that was used to build this {@code AnnotationEleme}, it may be retrieved from this
078     * {@code transient} field.
079     */
080    public final transient AnnotationMemberDeclaration annotationMemberDeclaration;
081
082
083    // ********************************************************************************************
084    // ********************************************************************************************
085    // Constructors
086    // ********************************************************************************************
087    // ********************************************************************************************
088
089
090    /**
091     * Instantiates a {@code AnnotationElem}, and peels out the {@code String's} from a JavaParser
092     * {@code AnnotationMemberDeclaration}
093     * 
094     * <BR /><BR /><B>EXCEPTIONS NOTE:</B> The underlying parser code can throw exceptions, and the
095     * exception chain, and exception tree in the package is quite dense.  Suffice it to say, they
096     * are all unchecked exceptions.
097     * 
098     * @param amd This can be retrieved in any number of ways from the JavaParser package.  The
099     * instantiation process will convert a Java-Parser from of an
100     * {@code AnnotationMemberDeclaration}, <B><I>into this Bridge form
101     * {@code class AnnotationElem}</I></B>.
102     * 
103     * <BR /><BR />Yes, this is redundant, but that's what a bridge is - a wrapper class to make
104     * the programmer's life easier. All the salient information a programmer would need when
105     * improving JavaDoc Documentation HTML Files is easily and simply encapsulated as lists of
106     * {@code String's} in the {@code class AnnotationElem}.
107     */
108    public AnnotationElem(AnnotationMemberDeclaration amd)
109    {
110        super(
111            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
112            // Declaration-Constructor Parameters
113            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
114
115            amd.getAnnotations(),       // annotations
116            amd.getModifiers(),         // modifiers
117            amd.getNameAsString(),      // name
118
119            // Currently, the preferred way to retrieve the "signature"
120            LexicalPreservingPrinter.print(LexicalPreservingPrinter.setup(amd)),
121
122            amd.getJavadocComment(),    // JavaDoc Comment
123            Entity.ANNOTATION_ELEM,
124            amd.getBegin()              //  The Signature Line-Number (Position)
125        );
126
127        // Just gets the 'type' of the Element
128        // For instance: Excuse[] Excuses, would return 'Excuse[]'
129
130        this.type = amd.getType().toString().trim();
131
132        // NOTE: There are only four allowable types in the first place:
133        // Any 'Enum', a 'String', a boolean, and an int.  There is simply no need to use the
134        // full-path full-package type-string. (or any array of these types)
135
136        this.typeJOW = StringParse.typeToJavaIdentifier(this.type);
137
138        // If there is a default-value for this annotation, retrieve it
139        Optional<Expression> oEx = amd.getDefaultValue();
140
141        this.defaultValue = oEx.isPresent()
142            ? LexicalPreservingPrinter.print(LexicalPreservingPrinter.setup(oEx.get())).trim()
143            : null;
144
145        // Save the Java Parser reference in a transiet field
146        this.annotationMemberDeclaration = amd;
147    }
148
149
150    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
151    // Private Constructor, Used by the clone() Method
152    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
153
154    private AnnotationElem(AnnotationElem other)
155    {
156        super(other);
157
158        // 'AnnotationElem' specific fields
159        this.type                           = other.type;
160        this.typeJOW                        = other.typeJOW;
161        this.defaultValue                   = other.defaultValue;
162        this.annotationMemberDeclaration    = other.annotationMemberDeclaration;
163    }
164
165
166    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
167    // Used Internally by 'SummaryHTMLFile'
168    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
169    //
170    // Ensures that the Version with longer type-information strings is used.
171    // Java Doc often uses longer type strings
172
173    AnnotationElem(AnnotationElem aeFromJavaParser, String jdTypeStr)
174    {
175        super(aeFromJavaParser);
176
177        // 'AnnotationElem' specific fields
178        this.type                           = jdTypeStr;
179        this.typeJOW                        = aeFromJavaParser.typeJOW;
180        this.defaultValue                   = aeFromJavaParser.defaultValue;
181        this.annotationMemberDeclaration    = aeFromJavaParser.annotationMemberDeclaration;
182    }
183
184
185
186    // ********************************************************************************************
187    // ********************************************************************************************
188    // toString(...)
189    // ********************************************************************************************
190    // ********************************************************************************************
191
192
193    /**
194     * Generates a {@code String} of this {@code Annotation Element}, with all information included.
195     * 
196     * @return A printable string of this {@code AnnotationElem}.
197     * 
198     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
199     * @see #toString(int)
200     */
201    public String toString()
202    {
203        String def = (defaultValue != null)
204            ? ("Default:      [" + StringParse.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
205                "]\n") 
206            : "";
207    
208        return
209            "Name:         [" + name + "]\n" +
210            "Declaration:  [" + StringParse.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
211            "Type:         [" + typeJOW + "]\n" +
212            "Modifiers:    [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
213            def +
214            "Line Numbers: [sig=" + signatureLineNumber + ", jdStart=" + jdStartLineNumber +
215                                    ", jdEnd=" + jdEndLineNumber + "]";
216    }
217
218    /**
219     * Generates a {@code String} of this {@code Annotation Element}, with all information
220     * included. This will also included any content requested by the {@code 'flags'} parameter.
221     * For this class ({@code class AnnotationElem}), the only additional information printed by
222     * this {@code 'toString'} method is the Java-Doc Comment {@code String}.
223     * 
224     * <BR /><BR />This {@code String} may also have UNIX color codes added.
225     * 
226     * @param flags These are the {@code toString(...)} flags from class {@code PF}
227     * ("Print Flags"). View available flags listed in class {@link PF}.
228     * 
229     * @return A printable {@code String} of this {@code AnnotationElem}.
230     * 
231     * @see PF
232     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
233     * @see #toString()
234     */
235    public String toString(int flags)
236    {
237        boolean color = (flags & UNIX_COLORS) > 0;
238
239        return
240            printedName("Element", 14, color) + 
241            printedDeclaration(14, color) +
242            "Type-JOW:     [" + typeJOW + "]\n" + 
243            printedModifiers(14) +
244            printedLineNumbers(14, color) +
245
246            // These are optional, they adds a '\n' AT THE BEGINNING if they are included
247            printedDefault(color) +
248            printedComments(14, color, (flags & JAVADOC_COMMENTS) > 0);
249    }
250
251    private String printedDefault(boolean color)
252    {
253        // They need to abbreviate, seems extremely "unlikely" - but just in case...
254        return (defaultValue == null)
255            ? ""
256            :  "\nDefault:      [" + (color ? BGREEN : "") +
257                StringParse.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
258                (color ? RESET : "") + "]";
259    }
260
261
262    // ********************************************************************************************
263    // ********************************************************************************************
264    // Clone, CompareTo & Equals Stuff
265    // ********************************************************************************************
266    // ********************************************************************************************
267
268
269    /**
270     * Java's {@code interface Cloneable} requirements.  This instantiates a new
271     * {@code AnnotationElem} with identical fields.
272     * 
273     * @return A new {@code AnnotationElem} whose internal fields are identical to this one.  A
274     * deep copy on all internal arrays is performed.  New arrays are instantiated.
275     */
276    public AnnotationElem clone()
277    { return new AnnotationElem(this); }
278
279    /**
280     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
281     * using the two elements' {@code 'name'} field.
282     * 
283     * @param ae Any other {@code AnnotationElem} to be compared to {@code 'this' AnnotationElem}
284     * 
285     * @return An integer that fulfills Java's
286     * {@code interface Comparable<AnnotationElem> public boolean compareTo(AnnotationElem ae)}
287     * method requirements.
288     */
289    public int compareTo(AnnotationElem ae)
290    { return (this == ae) ? 0 : this.name.compareTo(ae.name); }
291
292    /**
293     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
294     * other)} method.  This version of equals merely compares the name of the element defined.
295     * The presumption here is that the definition of an 'element' only has meaning - <I>at all</I>
296     * - inside the context of an {@code Annotation} where that element has been defined.  Since
297     * inside any {@code '.java'} {@code Annotation}, there may only be one element with a given
298     * name, this method shall return <B>TRUE</B> whenever the element being compared also has the
299     * same name.
300     * 
301     * @param other This may be any other {@code Annotation-Element}.  It is <I><B>strongly
302     * suggested</B></I> that {@code 'other'} be an {@code element} defined in the same
303     * {@code '.java'} source-code file as {@code 'this'} element.
304     * 
305     * @return This method returns <B>TRUE</B> when {@code 'this'} instance of
306     * {@code AnnotationElem} has the same {@code 'name'} as the name of input-parameter
307     * {@code 'other'}
308     */
309    public boolean equals(AnnotationElem other)
310    { return this.name.equals(other.name); }
311}