/*
 * $Revision: 1.7 $ $Date: 2005/05/22 14:58:43 $
 * Copyright (C) 2004-2005 SUGIMOTO Ken-ichi
 * 作成日: 2004/09/05
 */
package feat.v1.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.jibx.runtime.IUnmarshallingContext;

import feat.v1.InitializationException;
import feat.v1.ObjectUtil;
import feat.v1.ResponsePointer;
import feat.v1.StringUtil;
import feat.v1.Util;

public class CommandDeclaration implements ConfigElement {


    private ResponseDeclaration errorPageDec;
    private Class commandClass;
    private PreProcessDeclaration[] preProcessList;
    private Function[] preProcessFunctions;
    private FeatureDeclaration featureDecl;
    private Map responses;

    // JiBX
    private String name;
    private String errorPage;
    private String className;
    private String encoding;
    private String preProcess;
    private String response;


    public CommandDeclaration() {
        responses = new HashMap();
    }


    public String getName() {
        return name;
    }

    public ResponseDeclaration getErrorPage() {
        return errorPageDec;
    }

    // TODO createCommandInstance

    public Class getCommandClass() {
        return commandClass;
    }

    public String getEncoding() {
        return encoding;
    }

    public PreProcessDeclaration[] getPreProcessList() {
        return preProcessList;
    }
    public void setPreProcess(String p) {
        preProcess = p;
    }

    public Function[] getPreProcessFunctions() {
        return preProcessFunctions;
    }

    /**
     * このコマンドにマッピングされたレスポンスへのポインタを返す。
     * @param mappedName
     * @return 存在しない名前を指定したときはnullを返す
     */
    public ResponsePointer getResponsePointer(String mappedName) {
        return (ResponsePointer)responses.get(mappedName);
    }

    /**
     * このコマンドにマッピングされたレスポンスのマッピング名の一覧を返す。
     * @return
     */
    public String[] getResponseNames() {
        Set keys = responses.keySet();
        return (String[])keys.toArray(new String[keys.size()]);
    }


    public FeatureDeclaration getFeatureDeclaration() {
        return featureDecl;
    }
    /*public void setFeatureDeclaration(FeatureDeclaration featureDecl) {
        this.featureDecl = featureDecl;
    }*/

    public void postset(IUnmarshallingContext uctx) {
        featureDecl = (FeatureDeclaration)uctx.getStackObject(1);
    }




    public void init() throws InitializationException {
        FeatConfig cfg = getFeatureDeclaration().getFeatureConfig().getFeatConfig();


        if ( className == null )
            throw new InitializationException("コマンドクラスの名前が指定されていない");

        if ( response == null ) {
            throw new InitializationException("responseが指定されていない");
        }
        else {
            // レスポンスのリスト
            // name = [featureName::]responseName, ...
            String[] resp = Util.parseList(response);
            for(int i=0; i<resp.length; i++) {
                String[] pair = StringUtil.stripAll(StringUtil.split(resp[i], '='));
                ResponsePointer pointer = Util.parseResponseName(pair[1], getFeatureDeclaration().getName());
	            responses.put(pair[0], pointer);
            }
        }

        if ( errorPage != null ) {
            errorPageDec = getFeatureDeclaration().getResponseDeclaration(errorPage);
            if ( errorPageDec == null )
                throw new InitializationException(
                        "error-pageに指定されたページ \""+errorPage+"\" は定義されていない");
        }

        if ( preProcess == null ) {
            preProcess = "";
        }

        // pre-processのリスト
        if ( preProcess.length() > 0 ) {
            preProcessFunctions = Util.parseFunctionList(preProcess);
            preProcessList = new PreProcessDeclaration[preProcessFunctions.length];
            FeatureDeclaration featureDecl = getFeatureDeclaration();
            for(int i=0; i<preProcessFunctions.length; i++) {
                String ppname = preProcessFunctions[i].getName();
                preProcessList[i] = featureDecl.getPreProcessDeclaration(ppname);
                if ( preProcessList[i] == null )
                    throw new InitializationException("pre-processに指定された "+ppname+" は定義されていない");
            }
        }
        else
            preProcessList = new PreProcessDeclaration[0];
    }

    public void validate() throws InitializationException {
        FeatConfig cfg = getFeatureDeclaration().getFeatureConfig().getFeatConfig();
        try {
            commandClass = ObjectUtil.loadClass(
                    className, getFeatureDeclaration().getPackage());

            String[] responseNames = getResponseNames();
            for(int i=0; i<responseNames.length; i++) {
                ResponsePointer pointer = getResponsePointer(responseNames[i]);
	            ResponseDeclaration responseDecl = cfg.getFeatureDeclaration(pointer.getFeatureName())
	            									  .getResponseDeclaration(pointer.getName());
	            if ( responseDecl == null )
	                throw new InitializationException("レスポンス "+pointer+" は定義されていない");
            }
        }
        catch (ClassNotFoundException ex) {
            throw new InitializationException("コマンドクラス \""+className+"\" が見つからない");
        }
    }

}
