/*
 * $Id: CommandConfig.java 220 2007-07-16 10:32:15Z sugimotokenichi $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日: 2006/02/20
 */
package feat2.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import feat2.FeatErrors;
import feat2.config.type.Identifier;

/**
 * コマンドの設定。
 * @author SUGIMOTO Ken-ichi
 */
public class CommandConfig extends Config {

    private Identifier name;
    private Boolean createSession;
    private String encoding;
    private String scheme;
    private ArrayList actions;
    private ArrayList exceptions;
    private HashMap outputs;

    private boolean sorted;

    public CommandConfig() {
        actions = new ArrayList();
        exceptions = new ArrayList();
        outputs = new HashMap();

        sorted = false;
    }

    // プロパティ -------------------------------------------------------------

    public Boolean getCreateSession() {
        return createSession;
    }
    public void setCreateSession(Boolean createSession) {
        this.createSession = createSession;
    }

    public String getEncoding() {
        return encoding;
    }
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public Identifier getName() {
        return name;
    }
    public void setName(Identifier name) {
        this.name = name;
    }

    /**
     * @return
     */
    public String getScheme() {
        return scheme;
    }
    public void setScheme(String scheme) {
        this.scheme = scheme;
    }


    // インスタンスメソッド ---------------------------------------------------

    /*public void addBean(BeanConfig bean) {
        actionComponents.add(bean);
        bean.setParent(this);
    }

    public void addEffect(EffectConfig effect) {
        actionComponents.add(effect);
        effect.setParent(this);
    }

    public void addFetch(FetchConfig fetch) {
        actionComponents.add(fetch);
        fetch.setParent(this);
    }*/

    public void addAction(ActionConfigBase action) {
        actions.add(action);
        action.setParent(this);
        sorted = false;
    }

    public ActionConfigBase getActionComponentConfig(String name) {
        for(int i=0;i<actions.size(); i++) {
            ActionConfigBase conf = (ActionConfigBase)actions.get(i);
            if ( conf.getName().getValue().equals(name) ) {
                return conf;
            }
        }
        return null;
    }


    /**
     * アクションの実行順リストを返す。
     * @return
     */
    public ActionConfigBase[] getActions() throws ConfigurationException {

        if ( !sorted ) {
            actions = getExecutionList(actions);
            sorted = true;
        }

        return (ActionConfigBase[])actions.toArray(new ActionConfigBase[0]);

    }


    public void addException(ExceptionConfig exception) {
        exceptions.add(exception);
        exception.setParent(this);
    }


    /**
     * 指定の例外クラスをキャッチできる例外処理の設定オブジェクトを返す。
     * @param exclass
     * @return 見つからなければnullを返す
     */
    public ExceptionConfig getException(Class exclass) {

        for (Iterator it = exceptions.iterator(); it.hasNext();) {
            ExceptionConfig exc = (ExceptionConfig) it.next();
            if ( exc.getCatchClass().isAssignableFrom(exclass) )
                return exc;
        }

        return null;

    }


    /**
     * outputを追加する。
     * @param output
     */
    public void addOutput(OutputConfig output) {
        outputs.put(output.getName().getValue(), output);
        output.setParent(this);
    }

    public OutputConfig getOutputConfig(String name) {
        return (OutputConfig)outputs.get(name);
    }


    // Configのメソッド -------------------------------------------------------

    public String getElementName() {
        return "command";
    }

    public boolean validate(FeatErrors errs) {
        boolean ret = true;

        ret = ret && ConfigUtil.validateRequired(name, "name", this, errs);

        ret = ret && ConfigUtil.validate(actions.iterator(), errs);
        ret = ret && ConfigUtil.validate(exceptions.iterator(), errs);
        ret = ret && ConfigUtil.validate(outputs.values().iterator(), errs);

        return ret;
    }

    private ArrayList getExecutionList(List components) throws ConfigurationException {
        ArrayList ret = new ArrayList();
        Dependencies dep = new Dependencies();

        // 依存関係を作る

        for(int i=0; i<components.size(); i++) {

            ActionConfigBase config = (ActionConfigBase)components.get(i);
            dep.addDependency(config, null);

            // 入力が参照しているオブジェクトが依存先なので
            // これらをすべて依存関係に追加する

            InputConfigBase[] inputs = config.getInputs();
            for(int ii=0; ii<inputs.length; ii++) {

                if ( inputs[ii] instanceof InputObjectConfig ) {
                    String targetName = ((InputObjectConfig)inputs[ii]).getRef().getName();
                    ActionConfigBase target = getActionComponentConfig(targetName);
                    dep.addDependency(config, target);
                }

            }

        }

        // 実行順の決定

        while( dep.count() > 0 ) {

            Object o = dep.getIndependentObject();
            if ( o == null ) {

                // すべてのオブジェクトがどこかに依存しているので、循環参照
                throw new ConfigurationException("error.config.CommandConfig.recurrence");

            }

            dep.removeDependencies(o);
            ret.add(o);
        }

        return ret;
    }

}
