/*
 * $Id: OutputConfig.java 227 2007-12-02 14:59:12Z sugimotokenichi $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日: 2006/02/20
 */
package feat2.config;

import java.util.ArrayList;

import feat2.FeatError;
import feat2.FeatErrors;
import feat2.config.type.Identifier;
import feat2.config.type.IdentifierList;
import feat2.config.type.Scope;

/**
 * 出力の遷移の設定。
 * @author SUGIMOTO Ken-ichi
 */
public class OutputConfig extends Config {

    private Identifier name;
    private Identifier response;
    private ArrayList outputObjects;
    private Scope scope;

    public OutputConfig() {
        outputObjects = new ArrayList();
    }


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

    public Identifier getResponse() {
        return response;
    }
    public void setResponse(Identifier response) {
        this.response = response;
    }

    public void setOutputObjects(IdentifierList nameList) {

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

            String name = nameList.get(i).getValue();
            // ここではnull(scope未設定)を設定しておく。
            // validateのときにOutputConfigのscope値を設定。
            Mapping mp = new Mapping(name, name, null);
            outputObjects.add(mp);

        }

    }

    public Scope getScope() {
        return scope;
    }
    public void setScope(Scope scope) {
        this.scope = scope;
    }


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

    /*public void addOutputMapping(Identifier localName, Identifier outputName, Scope scope) {
        Mapping o = new Mapping(localName.getValue(), outputName.getValue(), scope);
        outputObjects.add(o);
    }*/

    public void addOutputMapping(String localName, String outputName, String scope) {
        Scope scopeObj = null;
        if ( scope != null )
            scopeObj = new Scope(scope);
        Mapping o = new Mapping(localName, outputName, scopeObj);
        outputObjects.add(o);
    }

    public Mapping[] getOutputMapping() {
        return (Mapping[])outputObjects.toArray(new Mapping[0]);
    }



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

    public Identifier getName() {
        return name;
    }

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

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

    public boolean validate(FeatErrors errs) {

        boolean ret = true;

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

        String responseName = response.getValue();
        if ( responseName != null && getFeatureConfig().getResponseConfig(responseName) == null )
            errs.add( new ConfigError(responseName, "response", ConfigError.TYPE_REFERRENCE_RESPONSE, FeatError.ERROR, this) );


        // mappingのチェック

        CommandConfig commandConf = (CommandConfig)getParent();
        for(int i=0; i<outputObjects.size(); i++) {

            Mapping m = (Mapping)outputObjects.get(i);
            if ( ConfigUtil.validateRequired(m.getLocalName(), "local-name", this, errs)
                    && ConfigUtil.validateRequired(m.getOutputName(), "output-name", this, errs) ) {

                // ローカル名、出力名の形式が正しいか

                if ( !Identifier.isIdentifier(m.localName) ) {
                    errs.add(new ConfigError(m.localName, "local-name", ConfigError.TYPE_VALUE_FORMAT, FeatError.ERROR, this));
                }
                if ( !Identifier.isIdentifier(m.outputName) ) {
                    errs.add(new ConfigError(m.outputName, "output-name", ConfigError.TYPE_VALUE_FORMAT, FeatError.ERROR, this));
                }

                // ローカル名のアクションが存在するか

                if ( commandConf.getActionComponentConfig(m.getLocalName()) == null ) {

                    errs.add(new ConfigError(m.getLocalName(), "local-name", ConfigError.TYPE_REFERRENCE, FeatError.ERROR, this) );

                }

            }
            else {
                ret = false;
            }

            // scopeが未設定だったらoutputのscopeをコピー

            if ( m.scope == null ) {
                // OutputConfigのscopeがnullの場合もあるが、そのまま代入してかまわない。
                // コマンド実行時、mappingのscopeがnullだったらrequestスコープとして扱われる。
                // @see Command#processOutput(CommandContext)
                m.scope = scope;
            }

        }

        return ret;
    }



    // 内部クラス -------------------------------------------------------------

    public class Mapping {

        String localName;
        String outputName;
        Scope scope;

        private Mapping(String localName, String outputName, Scope scope) {
            this.localName = localName;
            this.outputName = outputName;
            this.scope = scope;
        }

        public String getLocalName() {
            return localName;
        }

        public String getOutputName() {
            return outputName;
        }

        public Scope getScope() {
            return scope;
        }


    }

}