/*
 * $Revision: 220 $ $Date: 2007-07-16 19:32:15 +0900 $
 * Copyright (C) 2004-2006 SUGIMOTO Ken-ichi
 * 作成日: 2004/05/15
 */
package feat2.config;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;

import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import feat2.FeatException;
import feat2.ObjectUtil;

public class ConfigReader {

    //private static Log log = LogFactory.getLog(ConfigReader.class);

    /**
     * feat-config.xmlを読み込む。
     * @param appRoot アプリケーションのルートディレクトリ。
     * @param locator feat-config.xmlファイル。
     * @throws FeatException
     * @return FeatConfig
     */
    public static FeatConfig parseFeatConfig(FileLocator appRoot, FileLocator locator) throws ConfigurationIOException {

        Digester digester = null;
        FeatConfig config = null;

        InputStream in = null;
        try {
            // 設定ファイルの読み込み

            URL rule = ConfigReader.class.getClassLoader().getResource("feat2/rules/feat-config-rules.xml");
            digester = DigesterLoader.createDigester(rule);
            digester.setEntityResolver(new FeatEntityResolver());
            digester.setValidating(true);
            addConverter(digester);

            in = new BufferedInputStream(locator.openInputStream());
            config = (FeatConfig)digester.parse(in);
            config.setAppRootLocator(appRoot);
            config.setConfigFileLocator(locator);

            // Feature設定ファイルの読み込み

            Iterator it = config.getFeatures();
            while( it.hasNext() ) {
                FeatureConfig fc = (FeatureConfig)it.next();
                String featureConfigFilename = fc.getConfigFilename();

                if ( featureConfigFilename != null ) {

                    FileLocator featureConfigLocator = locator.newLocation(featureConfigFilename);

                    FeatureRootConfig feature = parseFeature(featureConfigLocator);

                    fc.setFeatureRoot(feature);
                    fc.setConfigFileLocator(featureConfigLocator);

                }
                else {

                    throw new ConfigurationException("error.config.feature.configFilename.null");

                }

            }

        }
        catch (SAXException ex) {
            throw new ConfigurationIOException(ex);
        }
        catch (IOException ex) {
            throw new ConfigurationIOException(ex);
        }
        finally {
            if ( in != null ) {
                try {
                    in.close();
                }
                catch (IOException ex) {
                    throw new ConfigurationIOException(ex);
                }
            }
        }
        return config;
    }


    /**
     * feature設定ファイルの読み込み。
     * @param config feature設定ファイル。
     * @throws FeatException
     * @return FeatureDeclaration
     */
    public static FeatureRootConfig parseFeature(FileLocator file) throws ConfigurationIOException {

        Digester digester = null;
        FeatureRootConfig feature = null;
        InputStream in = null;
        try {
            digester = DigesterLoader.createDigester(ConfigReader.class.getClassLoader().getResource("feat2/rules/feature-config-rules.xml"));
            digester.setEntityResolver(new FeatEntityResolver());
            digester.setValidating(true);
            addConverter(digester);

            in = new BufferedInputStream(file.openInputStream());
            feature = (FeatureRootConfig)digester.parse(in);
        }
        catch (SAXException ex) {
            throw new ConfigurationIOException(ex);
        }
        catch (IOException ex) {
            throw new ConfigurationIOException(ex);
        }
        finally {
            if ( in != null ) {
                try {
                    in.close();
                }
                catch (IOException ex) {
                    throw new ConfigurationIOException(ex);
                }
            }
        }

        return feature;
    }


    /**
     * リソースファイルを読み込む。
     * @param file
     * @return
     * @throws FeatException 読み込みに失敗した
     */
    public static Resources parseResource(FileLocator file) throws ConfigurationIOException {

        Digester digester = null;
        Resources resourcesDecl = null;
        InputStream in = null;

        try {
            digester = DigesterLoader.createDigester(ConfigReader.class.getClassLoader().getResource("feat2/rules/resource-rules.xml"));
            addConverter(digester);

            in = new BufferedInputStream(file.openInputStream());
            resourcesDecl = (Resources)digester.parse(in);
        }
        catch (IOException ex) {
            throw new ConfigurationIOException(ex);
        }
        catch (SAXException ex) {
            throw new ConfigurationIOException(ex);
        }
        finally {
            if ( in != null ) {
                try {
                    in.close();
                }
                catch (IOException ex) {
                    throw new ConfigurationIOException(ex);
                }
            }
        }

        return resourcesDecl;
    }

    private static void addConverter(Digester digester) {

        ConvertUtilsBean convertUtils = digester.getBeanUtils().getConvertUtils();
        ObjectUtil.setFeatConverters(convertUtils);

    }

}

class FeatEntityResolver implements EntityResolver {

    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if ( systemId.indexOf("feat-config.dtd") > -1 ) {
            return new InputSource(open("feat-config.dtd"));
        }
        else if ( systemId.indexOf("feature-config.dtd") > -1 ) {
            return new InputSource(open("feature-config.dtd"));
        }
        return null;
    }

    private InputStream open(String resourcePath) {
        ClassLoader loader = ConfigReader.class.getClassLoader();
        InputStream in = loader.getResourceAsStream(resourcePath);
        return in;
    }

}
