Add Javadoc comments to enhance code clarity
[cli-helper.git] / src / main / java / eu / svjatoslav / commons / cli_helper / parameter_parser / Option.java
1 /*
2  * Svjatoslav Commons - shared library of common functionality. Author: Svjatoslav Agejenko.
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.commons.cli_helper.parameter_parser;
6
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import static eu.svjatoslav.commons.cli_helper.parameter_parser.ParameterCount.NONE;
11 import static java.lang.String.join;
12 import static java.util.Collections.addAll;
13 import static java.util.stream.Collectors.joining;
14
15 /**
16  * Represents an option that can be provided on CLI.
17  * This class allows specifying whether the option is mandatory,
18  * the parameter count, a description, and any aliases for the option.
19  *
20  * @param <T> type of value that this option returns.
21  * @param <I> type of this option.
22  */
23 public abstract class Option<T, I extends Option> {
24
25     /**
26      * Purpose of this option, like: input image path, compression level, etc...
27      *
28      * Note: for describing option type there is {@link #describeFormat()}.
29      */
30     public final String description;
31
32     /**
33      * List of arguments for this parameter.
34      */
35     public final List<String> parameters = new ArrayList<>();
36     final ParameterCount parameterCount;
37
38     /**
39      * List of aliases for this option.
40      */
41     private final List<String> aliases = new ArrayList<>();
42
43     /**
44      * Indicates that at least one parameter is mandatory for this option.
45      */
46     protected boolean mandatory;
47
48     /**
49      * If this parameter was present in the commandline, then this boolean will
50      * be set to <code>true</code>.
51      */
52     private boolean isPresent;
53
54     /**
55      * Represents an option that can be provided on CLI.
56      * This class allows specifying whether the option is mandatory,
57      * the parameter count, a description, and any aliases for the option.
58      *
59      * @param mandatory        indicates whether the option is mandatory
60      * @param parameterCount   the number of parameters required for the option
61      * @param description      a description of the option
62      * @param aliases2         any additional aliases for the option
63      */
64     public Option(final boolean mandatory,
65                   final ParameterCount parameterCount, final String description,
66                   final String... aliases2) {
67
68         this.mandatory = mandatory;
69         this.description = description;
70         this.parameterCount = parameterCount;
71
72         // save aliases
73         addAll(aliases, aliases2);
74     }
75
76     public Option(final String description, final ParameterCount parameterCount) {
77         this.description = description;
78         this.parameterCount = parameterCount;
79     }
80
81     /**
82      * Adds additional aliases to the option.
83      *
84      * @param aliasArray    an array of strings representing the aliases to be added
85      * @return the modified option object
86      */
87     @SuppressWarnings("unchecked")
88     public I addAliases(final String... aliasArray) {
89
90         // save aliases
91         addAll(aliases, aliasArray);
92
93         return (I) this;
94     }
95
96     /**
97      * @param parameterString parameter to add
98      * @return <code>true</code> if no errors were found. <code>false</code>
99      * otherwise.
100      */
101     public boolean addParameter(final String parameterString) {
102         // check if arguments are allowed for this parameter
103         if (parameterCount.equals(NONE)) {
104             System.out
105                     .println("Error! No parameters are allowed for option(s): "
106                             + getAliasesAsString());
107             return false;
108         }
109
110         // check if multiple arguments are allowed
111         if ((!parameters.isEmpty())
112                 && (parameterCount.equals(ParameterCount.ONE))) {
113             System.out
114                     .println("Error! Only single parameter is allowed for argument(s): "
115                             + getAliasesAsString());
116             return false;
117         }
118
119         if (isValid(parameterString)) {
120             parameters.add(parameterString);
121             return true;
122         } else {
123             System.out.println("Error! Invalid parameter type for \"" + parameterString
124                     + "\". It shall be " + describeFormat() + ".");
125             return false;
126         }
127     }
128
129     /**
130      * @return Single line parameter type description. For example: "file", "date", "integer", "regular expression", etc..
131      * <p>
132      * Note: for argument purpose description there is {@link #description}
133      */
134     public abstract String describeFormat();
135
136     /**
137      * @return aliases for this parameter as string.
138      */
139     public String getAliasesAsString() {
140         return join(", ", aliases);
141     }
142
143     /**
144      * Returns the help message for this parameter.
145      *
146      * @return the help message as a string.
147      */
148     public String getHelp() {
149         final StringBuilder result = new StringBuilder();
150
151         // first line
152         result.append(getAliasesAsString());
153         if (!NONE.equals(parameterCount)) {
154             result
155                     .append(" (")
156                     .append(isMandatory() ? "mandatory, " : "")
157                     .append(describeFormat())
158                     .append(")");
159
160             if (parameterCount.equals(ParameterCount.ONE_OR_MORE))
161                 result.append("...");
162         }
163         result.append("\n");
164
165         // second line
166         result.append("    " + description + "\n");
167
168         return result.toString();
169     }
170
171     /**
172      * Returns the value of the object.
173      *
174      * @return the value of the object.
175      */
176     public abstract T getValue();
177
178     public boolean isMandatory() {
179         return mandatory;
180     }
181
182     /**
183      * @return <code>true</code> if this parameter was present in the commandline.
184      */
185     public boolean isPresent() {
186         return isPresent;
187     }
188
189     /**
190      * Sets the present status of this parameter.
191      *
192      * @param present <code>true</code> if this parameter is present in the command line,
193      *                <code>false</code> otherwise.
194      */
195     protected void setPresent(final boolean present) {
196         this.isPresent = present;
197     }
198
199     /**
200      * @param alias alias to check against
201      * @return <code>true</code> if given alias is registered for this
202      * parameter.
203      */
204     public boolean matchesAlias(final String alias) {
205         return aliases.contains(alias);
206
207     }
208
209     /**
210      * Notifies this option that no more parameters will follow.
211      * This gives option chance to verify if this is ok.
212      *
213      * @return <code>true</code> if no errors were found. <code>false</code>
214      * otherwise.
215      */
216     public boolean noMoreArguments() {
217
218         if ((!parameterCount.equals(NONE))
219                 && (parameters.isEmpty())) {
220
221             System.out.println("Error! " + getAliasesAsString()
222                     + " require at least one parameter.");
223
224             return false;
225         }
226         return true;
227     }
228
229     /**
230      * Sets the option as mandatory. This means that the option must be provided by the user
231      * in order for the program to run successfully.
232      *
233      * @return The updated instance of the option.
234      */
235     @SuppressWarnings("unchecked")
236     public I setMandatory() {
237         mandatory = true;
238         return (I) this;
239     }
240
241     /**
242      * @param value value to validate
243      * @return <code>true</code> if value is correct, <code>false</code>
244      * otherwise.
245      */
246     public abstract boolean isValid(String value);
247
248 }