001package Torello.JavaDoc.Annotations;
002
003import Torello.JDUInternal.Miscellaneous.EntityAnnotationData;
004
005import Torello.JavaDoc.Messager.Messager;
006import Torello.JavaDoc.Messager.MsgPrintTools;
007
008import Torello.JDUInternal.Miscellaneous.Where.JDUAnnotations;
009
010import Torello.Java.ReadOnly.ReadOnlyList;
011import Torello.Java.ReadOnly.ROArrayListBuilder;
012import Torello.Java.ReadOnly.ReadOnlyArrayList;
013
014import static Torello.Java.C.BRED;
015import static Torello.Java.C.RESET;
016
017import java.util.List;
018
019import com.sun.source.tree.Tree;
020import com.sun.source.tree.AnnotationTree;
021import com.sun.source.tree.IdentifierTree;
022import com.sun.source.tree.MemberSelectTree;
023
024
025/**
026 * This class is intended to contain / hold a single mirror instance for each 
027 * <B STYLE='color:red;'>Entity-Level Annotation</B> that has been placed on a single entity.
028 * 
029 * <BR /><BR />
030 * See: {@link Torello.JavaDoc.Entity Entity} - Methods, Fields, Constructors,
031 * Enumeration-Constants &amp; Annotation-Elements are referred to as "Entities" in JDU.
032 * 
033 * @see Torello.JavaDoc.Annotations.LinkJavaSource
034 * @see Torello.JavaDoc.Annotations.IntoHTMLTable
035 */
036public class EntityAnnotationMirrors  
037{
038    // ********************************************************************************************
039    // ********************************************************************************************
040    // An Empty-Mirror Reference
041    // ********************************************************************************************
042    // ********************************************************************************************
043
044
045    /**
046     * If there are ZERO annotations that have been placed on a particular "Entity" (Method, Field,
047     * Constructor, etc...), then there is no chance whatsoever that there are any JDU Annotations!
048     * In such cases, the entire constructor is skipeed, and this "EMPTY_MIRROR" is assigned,
049     * instead.
050     */
051    public static final EntityAnnotationMirrors EMPTY_MIRROR = new EntityAnnotationMirrors();
052
053    @SuppressWarnings("unchecked")
054    private EntityAnnotationMirrors()
055    {
056        this.ljsMirrors = ReadOnlyArrayList.emptyROAL();
057        this.ihtMirror  = null;
058    }
059
060
061    // ********************************************************************************************
062    // ********************************************************************************************
063    // The Actual Mirrors - as Fields of this class
064    // ********************************************************************************************
065    // ********************************************************************************************
066
067
068    /**
069     * {@code 'LinkJavaSource'} Data.
070     * 
071     * <BR /><BR />
072     * This is a "Repeatable Annotation", and thus this is not a single reference, but rather a
073     * "Read Only List" of references.  This pointer will never be null, instead if a particular
074     * {@link Torello.JavaDoc.Entity Entity} has not been adorned with any
075     * {@code '@LinkJavaSource'} annotations, then {@code 'ljsMirrors'} will be an empty list.
076     * 
077     * @see Torello.JavaDoc.Annotations.LinkJavaSource
078     */
079    public final ReadOnlyList<LJSMirror> ljsMirrors;
080
081    /**
082     * {@code 'IntoHTMLTable'} Data
083     * @see Torello.JavaDoc.Annotations.IntoHTMLTable
084     */
085    public final IHTMirror ihtMirror;
086
087
088    // ********************************************************************************************
089    // ********************************************************************************************
090    // Constructor: This is used (ONLY !) in class Torello.JavaDoc.Declaration
091    // ********************************************************************************************
092    // ********************************************************************************************
093
094
095    @SuppressWarnings("unchecked")
096    public EntityAnnotationMirrors(
097            final List<AnnotationTree>  annotList,
098            final String                signature,
099            final EntityAnnotationData  ead
100        )
101    {
102        // @LinkJavaSource is a @Repeatable Annotation ==> Keep Track of all of them
103        ROArrayListBuilder<LJSMirror> ljsROALB = new ROArrayListBuilder<>();
104
105
106        // @IntoHTMLTable is not *NOT* @Repeatable ==> it's an error to have more than one
107        // This is declared as non-final, because it is also "Optional", and because it needs to 
108        // be assigned to the actual final Instance-Field "ihtMirror".
109        // 
110        // NOTE: If you try to change this a third time, you are just goig to revert it back to the
111        //       way it is right now...
112
113        IHTMirror ihtMirror = null;
114
115        TOP:
116        for (AnnotationTree at : annotList)
117        {
118            Tree annotationType = at.getAnnotationType();
119
120            // Say: "Thank-You ChatGPT"
121            // That thing saved me a lot of time AND stress levels today.
122
123            final String annotationClassName;
124
125            if (annotationType instanceof IdentifierTree)
126            {
127                // This handles simple annotations, for instance: @SuppressWarnings and @Override
128                // NOTE: Chat-GPT explained this whole thing - where there are 2 kinds of
129                // "AnnotatinTypes" that are used by the Sun-Oracle Parser...
130                // 
131                // Unfortunately I forgot to write down what it said.  It was very right though !
132
133                annotationClassName = ((IdentifierTree) annotationType).getName().toString();
134
135                // System.out.println("\nIdentifierTree => annotationClassName: " + annotationClassName);
136            }
137
138            else if (annotationType instanceof MemberSelectTree)
139            {
140                // This handles fully qualified annotations like @java.lang.SuppressWarnings
141                annotationClassName = ((MemberSelectTree) annotationType).getIdentifier().toString();
142
143                // System.out.println("\nMemberSelectTree => annotationClassName: " + annotationClassName);
144            }
145
146            else
147            {
148                annotationClassName = null;
149
150                throw Messager.assertFail(
151                    BRED + "My Annotation Parser just bit the dust" + RESET + '\n' +
152                    "Extracted instance of 'com.sun.source.tree.AnnotationTree' was neither an " +
153                    "instance of 'IdentifierTree' nor 'MemberSelectTree'.\n" +
154                    "This is not supposed to be possible / This is unreachable code.\n" +
155                    "The returned Type / Class-Name was:\n" +
156                    BRED + annotationType.getClass().getCanonicalName() + RESET,
157                    JDUAnnotations.EntityAnnotationMirrors
158                );
159            }
160
161            switch (annotationClassName)
162            {
163                case "LinkJavaSource" :
164
165                    final LJSMirror ljsm = new LJSMirror(
166                        at.toString(),
167                        at.getArguments(),
168                        signature,
169                        ead.unParsedLJSFilesList,
170                        ead.allPkgLJSHandlesList
171                    );
172
173                    // Skip the Annotation completely if there were errors
174                    if (Messager.hadErrors()) break TOP;
175
176                    // System.out.println(at.toString() + '\n' + m.toString());
177                    ljsROALB.add(ljsm);
178
179                    break;
180
181
182                case "IntoHTMLTable" :
183
184                    if (ihtMirror != null) throw Messager.assertFail(
185                        "There appears to be a second instance of the @IntoHTMLTable " +
186                            "Annotation.  However, this is not a @Repeatable Annotation." +
187                        MsgPrintTools.annotationProcessingError(),
188                        JDUAnnotations.EntityAnnotationMirrors
189                    );
190
191
192                    // The parsed arguments to to the Annotation
193                    // final List<? extends ExpressionTree> arguments,
194                    // 
195                    // This is the Annotation, as a simple Java-String.  This is very useful for
196                    // Error-Printing with the Messager.  That's the only purpose of it
197                    // final String annotationAsStr,
198                    //
199                    // The Signature of the Detail-Entity onto which this "@LinkJavaSource"
200                    // Annotation was placed.  Very important for error messages
201                    // final String signature
202
203                    ihtMirror = new IHTMirror(at.getArguments(), at.toString(), signature);
204
205                    // Skip the Annotation completely if there were errors
206                    if (Messager.hadErrors()) break TOP;
207
208                    break;
209
210                default: continue TOP;
211            }
212        }
213
214        this.ljsMirrors = (Messager.hadErrors() || (ljsROALB.size() == 0))
215            ? ReadOnlyArrayList.emptyROAL()
216            : ljsROALB.build();
217
218        this.ihtMirror = ihtMirror;
219    }
220};