001/*
002 * Copyright 2003-2005 The Apache Software Foundation
003 * Copyright 2005 Stephen McConnell
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package net.dpml.cli.builder;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import net.dpml.cli.Argument;
023import net.dpml.cli.option.ArgumentImpl;
024import net.dpml.cli.resource.ResourceConstants;
025import net.dpml.cli.resource.ResourceHelper;
026import net.dpml.cli.validation.Validator;
027
028/**
029 * Builds Argument instances.
030 *
031 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
032 * @version @PROJECT-VERSION@
033 */
034public class ArgumentBuilder
035{
036    /** i18n */
037    private static final ResourceHelper RESOURCES = ResourceHelper.getResourceHelper();
038    
039    /** name of the argument. Used for display and lookups in CommandLine */
040    private String m_name;
041
042    /** description of the argument. Used in the automated online help */
043    private String m_description;
044
045    /** minimum number of values required */
046    private int m_minimum;
047
048    /** maximum number of values permitted */
049    private int m_maximum;
050
051    /** character used to separate the values from the option */
052    private char m_initialSeparator;
053
054    /** character used to separate the values from each other */
055    private char m_subsequentSeparator;
056
057    /** object that should be used to ensure the values are valid */
058    private Validator m_validator;
059
060    /** used to identify the consume remaining option, typically "--" */
061    private String m_consumeRemaining;
062
063    /** default values for argument */
064    private List m_defaultValues;
065
066    /** id of the argument */
067    private int m_id;
068
069    /**
070     * Creates a new ArgumentBuilder instance
071     */
072    public ArgumentBuilder()
073    {
074        reset();
075    }
076
077    /**
078     * Creates a new Argument instance using the options specified in this
079     * ArgumentBuilder.
080     * 
081     * @return A new Argument instance using the options specified in this
082     * ArgumentBuilder.
083     */
084    public final Argument create()
085    {
086        final Argument argument =
087            new ArgumentImpl(
088              m_name,
089              m_description,
090              m_minimum,
091              m_maximum,
092              m_initialSeparator,
093              m_subsequentSeparator,
094              m_validator,
095              m_consumeRemaining,
096              m_defaultValues,
097              m_id );
098        reset();
099        return argument;
100    }
101
102    /**
103     * Resets the ArgumentBuilder to the defaults for a new Argument. The
104     * method is called automatically at the end of a create() call.
105     * @return the argument builder
106     */
107    public final ArgumentBuilder reset()
108    {
109        m_name = "arg";
110        m_description = null;
111        m_minimum = 0;
112        m_maximum = Integer.MAX_VALUE;
113        m_initialSeparator = ArgumentImpl.DEFAULT_INITIAL_SEPARATOR;
114        m_subsequentSeparator = ArgumentImpl.DEFAULT_SUBSEQUENT_SEPARATOR;
115        m_validator = null;
116        m_consumeRemaining = "--";
117        m_defaultValues = null;
118        m_id = 0;
119        return this;
120    }
121
122    /**
123     * Sets the name of the argument. The name is used when displaying usage
124     * information and to allow lookups in the CommandLine object.
125     * 
126     * @see net.dpml.cli.CommandLine#getValue(String)
127     * 
128     * @param newName the name of the argument
129     * @return this ArgumentBuilder
130     */
131    public final ArgumentBuilder withName( final String newName )
132    {
133        if( newName == null )
134        {
135            throw new IllegalArgumentException(
136              RESOURCES.getMessage(
137                ResourceConstants.ARGUMENT_BUILDER_NULL_NAME ) );
138        }
139        if( "".equals( newName ) )
140        {
141            throw new IllegalArgumentException(
142              RESOURCES.getMessage(
143                ResourceConstants.ARGUMENT_BUILDER_EMPTY_NAME ) );
144        }
145        m_name = newName;
146        return this;
147    }
148
149    /**
150     * Sets the description of the argument.
151     * 
152     * The description is used when displaying online help.
153     * 
154     * @param newDescription a description of the argument
155     * @return this ArgumentBuilder
156     */
157    public final ArgumentBuilder withDescription( final String newDescription )
158    {
159        m_description = newDescription;
160        return this;
161    }
162
163    /**
164     * Sets the minimum number of values needed for the argument to be valid.
165     * 
166     * @param newMinimum the number of values needed
167     * @return this ArgumentBuilder
168     */
169    public final ArgumentBuilder withMinimum( final int newMinimum )
170    {
171        if( newMinimum < 0 )
172        {
173            throw new IllegalArgumentException(
174              RESOURCES.getMessage(
175                ResourceConstants.ARGUMENT_BUILDER_NEGATIVE_MINIMUM ) );
176        }
177        m_minimum = newMinimum;
178        return this;
179    }
180
181    /**
182     * Sets the maximum number of values allowed for the argument to be valid.
183     * 
184     * @param newMaximum the number of values allowed
185     * @return this ArgumentBuilder
186     */
187    public final ArgumentBuilder withMaximum( final int newMaximum )
188    {
189        if( newMaximum < 0 )
190        {
191            throw new IllegalArgumentException(
192              RESOURCES.getMessage(
193                ResourceConstants.ARGUMENT_BUILDER_NEGATIVE_MAXIMUM ) );
194        }
195        m_maximum = newMaximum;
196        return this;
197    }
198
199    /**
200     * Sets the character used to separate the values from the option. When an
201     * argument is of the form -libs:dir1,dir2,dir3 the initialSeparator would
202     * be ':'.
203     * 
204     * @param newInitialSeparator the character used to separate the values 
205     * from the option
206     * @return this ArgumentBuilder
207     */
208    public final ArgumentBuilder withInitialSeparator(
209        final char newInitialSeparator )
210    {
211        m_initialSeparator = newInitialSeparator;
212        return this;
213    }
214
215    /**
216     * Sets the character used to separate the values from each other. When an
217     * argument is of the form -libs:dir1,dir2,dir3 the subsequentSeparator
218     * would be ','.
219     * 
220     * @param newSubsequentSeparator the character used to separate the values 
221     * from each other
222     * @return this ArgumentBuilder
223     */
224    public final ArgumentBuilder withSubsequentSeparator(
225        final char newSubsequentSeparator )
226    {
227        m_subsequentSeparator = newSubsequentSeparator;
228        return this;
229    }
230
231    /**
232     * Sets the validator instance used to perform validation on the Argument
233     * values.
234     * 
235     * @param newValidator a Validator instance
236     * @return this ArgumentBuilder
237     */
238    public final ArgumentBuilder withValidator( final Validator newValidator )
239    {
240        if( newValidator == null )
241        {
242            throw new IllegalArgumentException(
243              RESOURCES.getMessage(
244                ResourceConstants.ARGUMENT_BUILDER_NULL_VALIDATOR ) );
245        }
246        m_validator = newValidator;
247        return this;
248    }
249
250    /**
251     * Sets the "consume remaining" option, defaults to "--". Use this if you
252     * want to allow values that might be confused with option strings.
253     * 
254     * @param newConsumeRemaining the string to use for the consume 
255     * remaining option
256     * @return this ArgumentBuilder
257     */
258    public final ArgumentBuilder withConsumeRemaining( final String newConsumeRemaining )
259    {
260        if( newConsumeRemaining == null )
261        {
262            throw new IllegalArgumentException(
263              RESOURCES.getMessage(
264                ResourceConstants.ARGUMENT_BUILDER_NULL_CONSUME_REMAINING ) );
265        } 
266        if( "".equals( newConsumeRemaining ) )
267        {
268            throw new IllegalArgumentException(
269              RESOURCES.getMessage(
270                ResourceConstants.ARGUMENT_BUILDER_EMPTY_CONSUME_REMAINING ) );
271        }
272        m_consumeRemaining = newConsumeRemaining;
273        return this;
274    }
275
276    /**
277     * Sets the default value.
278     * 
279     * @param defaultValue the default value for the Argument
280     * @return this ArgumentBuilder
281     */
282    public final ArgumentBuilder withDefault( final Object defaultValue )
283    {
284        if( defaultValue == null )
285        {
286            throw new IllegalArgumentException(
287              RESOURCES.getMessage(
288                ResourceConstants.ARGUMENT_BUILDER_NULL_DEFAULT ) );
289        }
290        
291        if( m_defaultValues == null )
292        {
293            m_defaultValues = new ArrayList( 1 );
294        }
295        m_defaultValues.add( defaultValue );
296        return this;
297    }
298
299    /**
300     * Sets the default values.
301     * 
302     * @param newDefaultValues the default values for the Argument
303     * @return this ArgumentBuilder
304     */
305    public final ArgumentBuilder withDefaults( final List newDefaultValues )
306    {
307        if( newDefaultValues == null )
308        {
309            throw new IllegalArgumentException(
310              RESOURCES.getMessage(
311                ResourceConstants.ARGUMENT_BUILDER_NULL_DEFAULTS ) );
312        }
313        m_defaultValues = newDefaultValues;
314        return this;
315    }
316
317    /**
318     * Sets the id
319     * 
320     * @param newId the id of the Argument
321     * @return this ArgumentBuilder
322     */
323    public final ArgumentBuilder withId( final int newId )
324    {
325        m_id = newId;
326        return this;
327    }
328}