001/**
002 * Copyright 2003-2004 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.HashSet;
020import java.util.Iterator;
021import java.util.Set;
022
023import net.dpml.cli.Argument;
024import net.dpml.cli.Option;
025import net.dpml.cli.validation.ClassValidator;
026import net.dpml.cli.validation.DateValidator;
027import net.dpml.cli.validation.FileValidator;
028import net.dpml.cli.validation.NumberValidator;
029import net.dpml.cli.validation.URLValidator;
030import net.dpml.cli.validation.Validator;
031
032/**
033 * Builds Options using a String pattern
034 *
035 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
036 * @version @PROJECT-VERSION@
037 */
038public class PatternBuilder 
039{
040    private final GroupBuilder m_gbuilder;
041    private final DefaultOptionBuilder m_obuilder;
042    private final ArgumentBuilder m_abuilder;
043    private final Set m_options = new HashSet();
044
045    /**
046     * Creates a new PatternBuilder
047     */
048    public PatternBuilder()
049    {
050        this(
051            new GroupBuilder(),
052            new DefaultOptionBuilder(),
053            new ArgumentBuilder() );
054    }
055
056    /**
057     * Creates a new PatternBuilder
058     * @param gbuilder the GroupBuilder to use
059     * @param obuilder the DefaultOptionBuilder to use
060     * @param abuilder the ArgumentBuilder to use
061     */
062    public PatternBuilder(
063        final GroupBuilder gbuilder,
064        final DefaultOptionBuilder obuilder,
065        final ArgumentBuilder abuilder )
066    {
067        m_gbuilder = gbuilder;
068        m_obuilder = obuilder;
069        m_abuilder = abuilder;
070    }
071
072    /**
073     * Creates a new Option instance.
074     * @return a new Option instance
075     */
076    public Option create()
077    {
078        final Option option;
079        if( m_options.size() == 1 )
080        {
081            option = (Option) m_options.iterator().next();
082        }
083        else
084        {
085            m_gbuilder.reset();
086            for( final Iterator i = m_options.iterator(); i.hasNext();)
087            {
088                m_gbuilder.withOption( (Option) i.next() );
089            }
090            option = m_gbuilder.create();
091        }
092        reset();
093        return option;
094    }
095
096    /**
097     * Resets this builder
098     * @return the builder
099     */
100    public PatternBuilder reset()
101    {
102        m_options.clear();
103        return this;
104    }
105
106    private void createOption( final char type, final boolean required, final char opt ) 
107    {
108        final Argument argument;
109        if( type != ' ' )
110        {
111            m_abuilder.reset();
112            m_abuilder.withValidator( validator( type ) );
113            if( required )
114            {
115                m_abuilder.withMinimum( 1 );
116            }
117            if( type != '*' )
118            {
119                m_abuilder.withMaximum( 1 );
120            }
121            argument = m_abuilder.create();
122        }
123        else
124        {
125            argument = null;
126        }
127
128        m_obuilder.reset();
129        m_obuilder.withArgument( argument );
130        m_obuilder.withShortName( String.valueOf( opt ) );
131        m_obuilder.withRequired( required );
132        m_options.add( m_obuilder.create() );
133    }
134
135    /**
136     * Builds an Option using a pattern string.
137     * @param pattern the pattern to build from
138     */
139    public void withPattern( final String pattern )
140    {
141        int sz = pattern.length();
142        char opt = ' ';
143        char ch = ' ';
144        char type = ' ';
145        boolean required = false;
146
147        for( int i=0; i < sz; i++ )
148        {
149            ch = pattern.charAt( i );
150            switch( ch ) 
151            {
152                case '!' :
153                    required = true;
154                    break;
155                case '@' :
156                case ':' :
157                case '%' :
158                case '+' :
159                case '#' :
160                case '<' :
161                case '>' :
162                case '*' :
163                case '/' :
164                    type = ch;
165                    break;
166                default :
167                    if( opt != ' ' )
168                    {
169                        createOption( type, required, opt );
170                        required = false;
171                        type = ' ';
172                    }
173                    opt = ch;
174            }
175        }
176        if( opt != ' ' )
177        {
178            createOption( type, required, opt );
179        }
180    }
181
182    private static Validator validator( final char c )
183    {
184        switch( c )
185        {
186            case '@' :
187                final ClassValidator classv = new ClassValidator();
188                classv.setInstance( true );
189                return classv;
190            case '+' :
191                final ClassValidator instancev = new ClassValidator();
192                return instancev;
193                //case ':':// no validator needed for a string
194            case '%' :
195                return NumberValidator.getNumberInstance();
196            case '#' :
197                return DateValidator.getDateInstance();
198            case '<' :
199                final FileValidator existingv = new FileValidator();
200                existingv.setExisting( true );
201                existingv.setFile( true );
202                return existingv;
203            case '>' :
204            case '*' :
205                return new FileValidator();
206            case '/' :
207                return new URLValidator();
208            default :
209                return null;
210        }
211    }
212}