/*
 * $Revision: 1.8 $ $Date: 2005/05/22 14:58:43 $
 * (C) 2004 SUGIMOTO Ken-ichi
 */

package feat.v1.config;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

import feat.v1.InitializationException;

/**
 * feature設定ファイルのドキュメント要素。
 */
public class FeatureDeclaration implements ConfigElement {

    private ResponseDeclaration homeResponse;
    private FeatureConfig featureConfig;
    private ResourcesDeclaration resources;

    // JiBX
    private String name;
    private String home;
    private String pkg;
    private String encoding;
    private boolean createSession;

    private ArrayList preProcesses;
    private ArrayList commands;
    private ArrayList views;
    private ArrayList responses;
    /** ResourcesDeclarationのリスト */
    private ArrayList resourceGroups;
    private ArrayList exceptions;

    public FeatureDeclaration() {
        resources = new ResourcesDeclaration();
    }

    public String getName() {
        return name;
    }

    public String getPackage() {
        return pkg;
    }

    public String getEncoding() {
        return encoding;
    }

    public boolean isCreateSession() {
        return createSession;
    }

    public ResponseDeclaration getHomeResponse() {
        return homeResponse;
    }

    public Iterator getResponses() {
        return responses.iterator();
    }

    public ResponseDeclaration getResponseDeclaration(String responseName) {
        if ( responseName == null )
            return null;

        if ( responseName.equals("#home") )
            return homeResponse;
        else
            return (ResponseDeclaration)ConfigUtil.find(responses, responseName);
    }

    public CommandDeclaration getCommand(String commandName) {
        return (CommandDeclaration)ConfigUtil.find(commands, commandName);
    }

    public String[] getCommandNames() {
        String[] ret = new String[commands.size()];
        for(int i=0; i<ret.length; i++) {
            ret[i] = ((CommandDeclaration)commands.get(i)).getName();
        }
        return ret;
    }

    public PreProcessDeclaration getPreProcessDeclaration(String preProcessName) {
        return (PreProcessDeclaration)ConfigUtil.find(preProcesses, preProcessName);
    }

    public ViewDeclaration getView(String viewName) {
        return (ViewDeclaration)ConfigUtil.find(views, viewName);
    }

    /**
     * 指定された例外を処理する例外ハンドラの宣言を返す。
     * 例外ハンドラはcatch文と同様にその例外クラスとサブクラスの例外を処理する。
     * また、例外を処理する例外ハンドラを見つける順番は設定ファイルに記述された順となる。
     * @param ex
     * @return 例外ハンドラの宣言。見つからなかったときはnullを返す
     */
    public ExceptionDeclaration getExceptionDeclaration(Exception ex) {
        for(int i=0; i<exceptions.size(); i++) {
            ExceptionDeclaration exDecl = (ExceptionDeclaration)exceptions.get(i);
            if ( exDecl.getType().isInstance(ex) ) {
                return exDecl;
            }
        }
        return null;
    }

    /**
     * リソース文字列を返す。
     * @param name リソース名
     * @param locale ロケール。nullでも良い
     * @return
     */
    public String getStringResource(String name, Locale locale) {
        return resources.getString(name, locale);
    }

    /**
     * リソース名をすべて返す。
     * @return ソートされたリソース名の集合。
     */
    public Set getResourceNames() {
        return resources.getReourceNames();
    }

    public void addResources(ResourcesDeclaration res) {
        resources.addResources(res);
    }

    /**
     * @return featureConfig を戻します。
     */
    public FeatureConfig getFeatureConfig() {
        return featureConfig;
    }
    /**
     * @param featureConfig featureConfig を設定。
     */
    public void setFeatureConfig(FeatureConfig featureConfig) {
        this.featureConfig = featureConfig;
    }

    // ConfigElementの実装

    public void init() throws InitializationException {

        if ( preProcesses == null )
            throw new InitializationException("preProcesses is null");
        if ( commands == null )
            throw new InitializationException("commands is null");
        if ( views == null )
            throw new InitializationException("views is null");
        if ( responses == null )
            throw new InitializationException("responses is null");
        if ( exceptions == null )
            throw new InitializationException("exceptions is null");

        // home
        if ( home == null )
            homeResponse = null;
        else {
            homeResponse = getResponseDeclaration(home);
            if ( homeResponse == null )
                throw new InitializationException("homeに指定されているページ ("+home+") は定義されていない");
        }

        if ( pkg == null )
            pkg = "";

        // リソース
        for(int i=0; i<resourceGroups.size(); i++) {
            ResourcesDeclaration r = (ResourcesDeclaration)resourceGroups.get(i);
            r.init();
            resources.addResources(r);
        }

        ConfigUtil.init(preProcesses);
        ConfigUtil.init(commands);
        ConfigUtil.init(views);
        ConfigUtil.init(responses);
        ConfigUtil.init(exceptions);
    }

    public void validate() throws InitializationException {
        ConfigUtil.validate(preProcesses);
        ConfigUtil.validate(commands);
        ConfigUtil.validate(views);
        ConfigUtil.validate(responses);
        ConfigUtil.validate(exceptions);
    }

}
