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.EnumConstantDeclaration;
009
010import static Torello.HTML.Tools.JavaDoc.PF.*;
011
012import Torello.Java.*;
013
014import java.util.function.Consumer;
015
016/**
017 * <B STYLE='color:darkred;'>Java Parser Bridge:</B>
018 * 
019 * Holds all information extracted from <CODE>'&#46;java' enum</CODE> Source Files about 
020 * Enumerated Constants's identified in that {@code 'enum'} file.
021 * 
022 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_GET_INST>
023 * <EMBED CLASS="external-html" DATA-FILE-ID=JPB_ENUM_CONST>
024 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
025 */
026@JDHeaderBackgroundImg(EmbedTagFileID={"ENUM_CONSTANT", "REFLECTION_EXTENSION"})
027public class EnumConstant
028    extends Declaration
029    implements java.io.Serializable, Comparable<EnumConstant>, Cloneable
030{
031    /** <EMBED CLASS="external-html" DATA-FILE-ID="SVUID"> */
032    public static final long serialVersionUID = 1;
033
034
035    // ********************************************************************************************
036    // ********************************************************************************************
037    // Param-Expressions
038    // ********************************************************************************************
039    // ********************************************************************************************
040
041
042    /**
043     * The parameters passed to the constructor that constructed the enumerated-constant instance.
044     * 
045     * <BR /><BR />Many {@code enum's} do not use constructors for their constants - using a
046     * constructor is an extra-feature that allows other, informational data to be ascribed to the
047     * constant.  If no constructor was used, then there (obviously) couldn't have been any
048     * expressions passed to a constructor for the constant.  In such cases, this field will be
049     * null.
050     * 
051     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_PI_ARR_NOTE>
052     */
053    protected final String[] paramExpressions;
054
055    /**
056     * Retrieves the list of {@code 'paramExpressions'} - <I>which may or may not have been used
057     * to construct this constant</I> - as {@code String}-array.  
058     * 
059     * @return An instance of {@code String[]} that employs the {@code clone()} method of the
060     * internal data-structure, <I>protecting its contents</I>.  If this {@code EnumConstant} did
061     * not employ a constructor, or that constructor was a zero-argument constructor, then this
062     * method will return null.
063     */
064    public String[] getParamExpressions()
065    { return (paramExpressions != null) ? paramExpressions.clone() : null; }
066
067    /**
068     * Invokes a user-provided {@code Consumer} with each of the {@code String's} contained by the
069     * internal {@code String[]}-Array {@link #paramExpressions}.
070     * 
071     * @param acceptParamExpressionAsStringConsumer 
072     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_CONSUM
073     *      DATA-P1=getParamExpressions DATA-P2="Enumerated Constants">
074     * 
075     * @see #paramExpressions
076     */
077    public void getParamExpressions(Consumer<String> acceptParamExpressionAsStringConsumer)
078    {
079        if (paramExpressions != null)
080            for (String paramExpression : paramExpressions)
081                acceptParamExpressionAsStringConsumer.accept(paramExpression);
082    }
083
084    /**
085     * Reports whether this instance of {@code EnumConstant} was constructed using a constructor
086     * that accepts parameters.  This method simply returns whether or not the internal
087     * {@link #paramExpressions} array is non-null and has length bigger than zero.
088     * 
089     * @return Returns {@code TRUE} if there were any modifiers - <I>{@code public, static, final}
090     * etc...</I> - that were specified in this declaration.
091     * 
092     * @see #paramExpressions
093     */
094    public boolean hasParamExpressions()
095    { return (paramExpressions != null) ? (paramExpressions.length > 0) : false; }
096
097    /**
098     * Return the number of parameters that are employed by the constructor that built this
099     * instance of {@code EnumConstant}.  If a constructor was not used to build this constant,
100     * or if that constructor doesn't require or accept parameters, then this method simply
101     * returns 0.
102     * 
103     * @return Returns the length of the {@code protected} (internal) {@link #paramExpressions}
104     * array, or zero if that array is null.
105     * 
106     * @see #paramExpressions
107     */
108    public int numParamExpressions()
109    { return (paramExpressions != null) ? paramExpressions.length : 0; }
110
111
112    // ********************************************************************************************
113    // ********************************************************************************************
114    // Java Parser Reference-Hook
115    // ********************************************************************************************
116    // ********************************************************************************************
117
118
119    /**
120     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JP_HOOK_FLD>
121     * 
122     * If a user decides to make use of the Java-Parser {@code EnumConstantDeclaration} instance
123     * that was used to build this {@code EnumConstant}, it may be retrieved from this
124     * {@code transient} field.
125     */
126    public final transient EnumConstantDeclaration enumConstantDeclaration;
127
128
129    // ********************************************************************************************
130    // ********************************************************************************************
131    // Constructors
132    // ********************************************************************************************
133    // ********************************************************************************************
134
135
136    /**
137     * Instantiates a {@code EnumConstant}, and peels out the {@code String's} from a JavaParser
138     * {@code EnumConstantDeclaration}
139     * 
140     * <BR /><BR /><B>EXCEPTIONS NOTE:</B> The underlying parser code can throw exceptions, and the
141     * exception chain, and exception tree in the package is quite dense.  Suffice it to say, they
142     * are all unchecked exceptions.
143     * 
144     * @param ecd This can be retrieved in any number of ways from the JavaParser package.  The
145     * instantiation process will convert a Java-Parser from of an {@code EnumConstantDeclaration},
146     * <B><I>into this Bridge form {@code class EnumConstant}</I></B>.
147     * 
148     * <BR /><BR />Yes, this is redundant, but that's what a bridge is - a wrapper class to make
149     * the programmer's life easier. All the salient information a programmer would need when
150     * improving JavaDoc Documentation HTML Files is easily and simply encapsulated as lists of
151     * {@code String's} in the {@code class EnumConstant}.
152     */
153    @SuppressWarnings("unchecked") // The Empty NodeList cast
154    public EnumConstant(EnumConstantDeclaration ecd)
155    {
156        super(
157            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
158            // Parameters for the constructor of parent abstract class "Declaration"
159            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
160
161            ecd.getAnnotations(),                       // Any annotations attached to this
162            (NodeList<Modifier>) EMPTY_NL,              // enum-contants can't modifiers!
163            ecd.getNameAsString(),                      // name
164            LexicalPreservingPrinter.print              // signature
165                (LexicalPreservingPrinter.setup(ecd)),
166            ecd.getJavadocComment(),                    // JavaDoc Comment
167            Entity.ENUM_CONSTANT,                       // Simple ENUM, instead of 'getClass()'
168            ecd.getBegin()                              // Signature Line Number (Position)
169        );
170
171        // Fill in the 'EnumConstant' fields ==> which are the parameters to the Enum-Constant
172        // Constructor.  Remember a very large percentage of Enum Constants will not have any
173        // "Constructor Parameters" - but for those that do, 'paramExpressions' will save them.
174
175        NodeList<Expression> args = ecd.getArguments();
176
177        paramExpressions = (args.size() > 0) ? new String[args.size()] : null;
178
179        int i=0;
180        for (Expression e : args) paramExpressions[i++] = e.toString().trim();
181
182        // Save the Java Parser instance in a transient field
183        this.enumConstantDeclaration = ecd;
184    }
185
186
187    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
188    // Used Internally by 'JavaDocHTMLFile'
189    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
190
191    /*
192    // DON'T DELETE THESE COMMENTS.  The Java Parser 'from Java Doc' **WILL NOT**
193    // come back, BUT it helps to know how to do that.
194    @SuppressWarnings("unchecked") // The Empty NodeList cast
195    @Deprecated
196    EnumConstant(String name)
197    {
198        // JavaDoc will literally generate nothing other than the name for an enum-constant
199        // This is fine/expected, but the JavaDoc generated 'EnumConstant' will have only the name!
200
201        super(
202            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
203            // Parameters for the constructor of parent abstract class "Declaration"
204            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
205            (NodeList<AnnotationExpr>) EMPTY_NL,    // annotations
206            (NodeList<Modifier>) EMPTY_NL,          // modifiers
207            name,                                   // name
208            name,                                   // signature
209            null                                    // JavaDoc Comment
210        );
211
212        this.paramExpressions = StringParse.EMPTY_STR_ARRAY;
213    }
214    */
215
216
217    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
218    // Private Constructor, Used by the clone() Method
219    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
220
221    private EnumConstant(EnumConstant other)
222    {
223        super(other);
224
225        this.enumConstantDeclaration = other.enumConstantDeclaration;
226
227        this.paramExpressions =
228            (other.paramExpressions != null) ? other.paramExpressions.clone() : null;
229    }
230
231
232    // ********************************************************************************************
233    // ********************************************************************************************
234    // toString()
235    // ********************************************************************************************
236    // ********************************************************************************************
237
238
239    /**
240     * Generates a {@code String} of this {@code Enum Constant}, with all information included.
241     * 
242     * @return A printable {@code String} of this {@code EnumConstant}.
243     * 
244     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
245     * @see #toString(int)
246     */
247    public String toString()
248    {
249        return
250            "Name:         [" + name + "]\n" +
251            "Declaration:  [" + StringParse.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
252            "Line Numbers: [sig=" + signatureLineNumber + ", jdStart=" + jdStartLineNumber +
253                                    ", jdEnd=" + jdEndLineNumber + "]";
254    }
255
256    /**
257     * Generates a {@code String} of this {@code EnumConst}, with all information included. This
258     * will also included any content requested by the {@code 'flags'} parameter.  For this class
259     * ({@code EnumConstant}), the only additional information printed by this {@code 'toString'} 
260     * method is the Java-Doc Comment {@code String}.
261     * 
262     * <BR /><BR />This {@code String} may also have UNIX color codes added.
263     * 
264     * @param flags These are the {@code toString(...)} flags from class {@code PF}
265     * ("Print Flags"). View available flags listed in class {@link PF}.
266     * 
267     * @return A printable {@code String} of this {@code AnnotationElem}.
268     * 
269     * @see PF
270     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
271     * @see #toString()
272     */
273    public String toString(int flags)
274    {
275        boolean color = (flags & UNIX_COLORS) > 0;
276
277        return
278            printedName("Enum-Const", 17, color) + 
279            printedDeclaration(17, color) +
280            printedParamExpressions(17) +
281            printedLineNumbers(17, color) +
282
283            // This are optional, it adds a '\n' AT THE BEGINNING if it is included
284            printedComments(17, color, (flags & JAVADOC_COMMENTS) > 0);
285    }
286
287    private String printedParamExpressions(int LEN)
288    {
289        if ((paramExpressions == null) || (paramExpressions.length == 0))
290            return "";
291
292        return StringParse.rightSpacePad("Initializer:", LEN) +
293            "[" + StrCSV.toCSV(paramExpressions, false, false, null) + "]\n";
294    }
295
296
297    // ********************************************************************************************
298    // ********************************************************************************************
299    // Clone, CompareTo & Equals 
300    // ********************************************************************************************
301    // ********************************************************************************************
302
303
304    /**
305     * Java's {@code interface Cloneable} requirements.  This instantiates a new
306     * {@code EnumConstant} with identical fields.
307     * 
308     * @return A new {@code EnumConstant} whose internal fields are identical to this one.  A
309     * deep copy on all internal arrays is performed.  New arrays are instantiated.
310     */
311    public EnumConstant clone()
312    { return new EnumConstant(this); }
313
314    /**
315     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
316     * using the two constants' {@code 'name'} field.
317     * 
318     * @param ec Any other {@code EnumConstant} to be compared to {@code 'this' EnumConstant}
319     * 
320     * @return An integer that fulfills Java's
321     * {@code interface Comparable<EnumConstant> public boolean compareTo(EnumConstant ec)}
322     * method requirements.
323     */
324    public int compareTo(EnumConstant ec)
325    { return (this == ec) ? 0 : this.name.compareTo(ec.name); }
326
327    /**
328     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
329     * other)} method.  This version of equals merely compares the name of the constant defined.
330     * The presumption here is that the definition of an 'constant' only has meaning - <I>at
331     * all</I> - inside the context of an {@code enum} where that constant has been defined.  Since
332     * inside any {@code '.java'} {@code enum}, there may only be one element with a given name,
333     * this method shall return <B>TRUE</B> whenever the constant being compared also has the same
334     * name.
335     * 
336     * @param other This may be any other {@code EnumConstant}.  It is <I><B>strongly
337     * suggested</B></I> that {@code 'other'} be a {@code constant} defined in the same
338     * {@code '.java'} source-code file as {@code 'this'} constant.
339     * 
340     * @return This method returns <B>TRUE</B> when {@code 'this'} instance of
341     * {@code EnumConstant} has the same {@code 'name'} as the name of input-parameter
342     * {@code 'other'}
343     */
344    public boolean equals(EnumConstant other)
345    { return this.name.equals(other.name); }
346}