/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/util/org/apache/slide/util/cli/CommandLine.java,v 1.1 2004/03/25 16:18:11 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:18:11 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.slide.util.cli;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.util.Strings;

public class CommandLine {
    public static CommandLine forString(String str) throws Abort {
        CommandLine cl;
        String[] formals;
        int i;
        String[] current;
        
        cl = new CommandLine(false);
        formals = Strings.split(str, "+");
        Strings.trim(formals);
        for (i = 0; i < formals.length; i++) {
            current = Strings.split(formals[i], " ");
            Strings.trim(current);
            switch (current.length) {
                case 2:
                    cl.add(new Formal(current[0], current[1], null));
                    break;
                case 3:
                    cl.add(new Formal(current[0], current[1], current[2]));
                    break;
                default:
                    throw new Abort("illegal argument spec: no=" + i + " count=" + current.length + ": '" + formals[i] + "'");
            }
        }
        return cl;
    }
    
    //--
    
    private final boolean additionals;
    private final List formals;
    
    public CommandLine(boolean additionals) {
        this.additionals = additionals;
        this.formals = new ArrayList();
    }
    
    public List getFormals() {
        return formals;
    }
    
    public void addLiteral(String name, String literal) {
        addLiterals(name, new String[] { literal }, literal);
    }
    
    public void addLiterals(String name, String[] literals, String value) {
        int i;
        
        for (i = 0; i < literals.length; i++) {
            add(new Formal(name, literals[i], value));
        }
    }
    
    public void addAlternatives(String name, String[] literals) {
        int i;
        
        for (i = 0; i < literals.length; i++) {
            add(new Formal(name, literals[i], literals[i]));
        }
    }
    
    public void addOption(String name) {
        add(new Formal(name, "-" + name, null));
    }
    
    public void addSwitch(String name) {
        add(new Formal(name, "-" + name, name));
    }
    
    
    public void add(Formal formal) {
        formals.add(formal);
    }
    
    
    public Actuals parse(String[] actuals) throws Abort {
        Actuals result;
        String actual;
        int i;
        Formal formal;

        result = new Actuals();
        for (i = 0; i < actuals.length; i++) {
            actual = actuals[i];
            formal = getFormal(actual);
            if (formal == null) {
                if (additionals) {
                    result.addAdditional(actual);
                } else {
                    // TODO: configurable -- the proper message had to use 'parameter', not 'action'?
                    throw new Abort("unkown action: " + actual);
                }
            } else {
                if (result.getSwitch(formal.name)) {
                    throw new Abort("too many values for parameter '" + formal.name + "'");
                }
                if (formal.value == null) {
                    if (i + 1 >= actuals.length) {
                        throw new Abort("missing argument for option '" + actual + "'");
                    }
                    result.add(formal.name, actuals[++i]);
                } else {
                    result.add(formal.name, formal.value);
                }
            }
        }
        return result;
    }
    
    public Formal getFormal(String key) {
        Iterator iter;
        Formal f;
        
        iter = formals.iterator();
        while (iter.hasNext()) {
            f = (Formal) iter.next();
            if (f.literal.equals(key)) {
                return f;
            }
        }
        return null;
    }
}
