/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Nicolas Christin
 * Contributor(s): ______________________________________.
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.newbean;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import org.apache.velocity.VelocityContext;


/**
 * This class represents a parameter the user may be prompted for. It
 * is responsible for asking the user for a value, validating his
 * input, exporting relevant datas into Velocity's context, and
 * deciding what should be the next parameter to ask.<p>
 *
 * A parameter is created by subclassing this class and overriding the
 * following abstract methods:
 *
 * <ul>
 *   <li>{@link #getPrompt()}</li>
 *   <li>{@link #isValid()}</li>
 *   <li>{@link #export()}</li>
 *   <li>{@link #getNextParameter()}</li>
 * </ul>
 */
public abstract class Parameter {

    private static final String PROMPT = "> ";
    private static final int INPUT_BUFFER_SIZE = 80;
    private static BufferedReader reader =
        new BufferedReader(new InputStreamReader(System.in));

    /** 
     * The Velocity context into which this parameter's variables will
     * be exported.
     */
    protected VelocityContext vContext = null;

    /**
     * This parameter's value, as entered by the user.
     */
    protected String value = null;

    
    /**
     * Creates a new parameter that will export its variables into the
     * specified Velocity context.
     *
     * @param context the Velocity context into which variables will
     * be exported
     */
    public Parameter(VelocityContext context) {
        vContext = context;
    }


    /**
     * Recusively walk through the parameters graph, obtaining
     * parameter ({@link #obtainValue()}) values and exporting ({@link
     * #export()}) them.<p>
     *
     * The path taken through the parameter graph may change depending
     * on the values entered by the user. It is determined after each
     * valid input by a call to {@link #getNextParameter()}.
     */
    public void walkThrough() {
        obtainValue();
        export();
        Parameter nextParameter = getNextParameter();
        if (nextParameter != null) {
            nextParameter.walkThrough();
        }
    }


    /**
     * Obtains the value of this parameter. This method prompts the
     * user for a value, stores it into {@link #value} through the
     * {@link #isValid()}. This process is repeated until the value is
     * valid.
     */
    public void obtainValue() {

		// check first if a cmd-line value has been specified
		String	inp = getCmdArg( getArgKeyword() );
		if( inp!=null ) {
			setValue(inp);
			if( isValid() ) { return; }
		}

        for (;;) {
            String input = null;
            System.out.println(getPrompt());
            System.out.print("> ");
            try {
                input = reader.readLine();
            } catch (IOException e) {
                NewBean.error(e.toString());
            }
            if (input == null) {
                input = "";
            }
            setValue(input);
            if (isValid())
                break;
            System.out.println("Invalid value, please retry");
        }
        System.out.println();
    }


    /**
     * Sets the {@link #value} of this parameter. This method is
     * called each time a value is entered is entered by the user,
     * before its validity has been checked.<p>
     *
     * This implementation simply sets {@link #value} to
     * <code>input</code>. You can override this method if you need to
     * format this input, for example to convert it to uppercase.
     */
    public void setValue(String input) {
        value = input;
    }


    /**
     * Returns the string used to prompt the user for a value.
     * @return the string used to prompt the user for a value.
     */
    public abstract String getPrompt();


    /**
     * Indicates whether this parameter as a valid value. This method
     * can safely assume {@link #value} is not <code>null</code>.
     *
     * @return <code>true</code> if {@link #value} is valid,
     * <code>false</code> otherwise
     */
    public abstract boolean isValid();


    /**
     * Exports the variables managed by this parameter into the
     * associated Velocity context (<i>ie</i> {@link #vContext}).
     */
    public abstract void export();


    /**
     * Returns the parameter the user will be asked for after this
     * one. This method is not invoked before a valid value has been
     * entered for this parameter; therefor it is possible to decide
     * which object to return based on the value of {@link #value}.<p>
     *
     * This method returns <code>null</code> if their is no more
     * parameters.
     *
     * @return the next parameter the user should be prompted for
     */
    public abstract Parameter getNextParameter();

	/**
	 * @return the command line keyword string for this parameter
	 */
	public abstract String		getArgKeyword();

	private String				getCmdArg( String kwd )
	{
		return (String)NewBean.commandLine.get( kwd );
	}

}
