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

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import feat2.config.BasicFileLocator;
import feat2.config.ClassLoaderFileLocator;
import feat2.config.ConfigReader;
import feat2.config.ConfigurationIOException;
import feat2.config.FileLocator;
import feat2.config.Resources;
import feat2.config.URLFileLocator;

/**
 * リソースを管理するクラス。
 * @author SUGIMOTO Ken-ichi
 */
public class FileResourceManager implements ResourceManager {

    private static FileResourceManager defaultRM = null;
    private static final Object lock = new Object();
    private static Log log = LogFactory.getLog(FileResourceManager.class);

    public static FileResourceManager getInstance() {

        synchronized (lock) {
            if ( defaultRM == null ) {

                try {
                    defaultRM = new FileResourceManager();
                    defaultRM.addResourceFile(new ClassLoaderFileLocator("resources.xml", FileResourceManager.class.getClassLoader()));
                }
                catch (IllegalArgumentException ex) {
                    log.error("", ex);
                }
                catch (URISyntaxException ex) {
                    log.error("", ex);
                }

            }
        }

        return defaultRM;

    }

    private Resources resources;
    private Locale locale;


    /**
     * デフォルトロケールのリソースマネージャを作成する。
     */
    public FileResourceManager() {
        this(Locale.getDefault());
    }

    /**
     * 指定のロケールのリソースマネージャを作成する。
     */
    public FileResourceManager(Locale locale) {
        resources = new Resources();
        if ( locale == null )
            this.locale = Util.NULL_LOCALE;
        else
            this.locale = locale;
    }

    /**
     * リソースファイルの内容を追加する。
     * 重複するリソースは上書きされる。
     * @param file
     */
    public void addResourceFile(File file) {
        try {
            addResourceFile(new BasicFileLocator(file));
        }
        catch (IllegalArgumentException ex) {
            log.warn("IllegalArgumentException - "+ex.getMessage());
        }
    }

    /**
     * リソースファイルの内容を追加する。
     * 重複するリソースは上書きされる。
     * @param url
     */
    public void addResourceFile(URL url) {
        try {
            addResourceFile(new URLFileLocator(url));
        }
        catch (IllegalArgumentException ex) {
            log.warn("IllegalArgumentException - "+ex.getMessage());
        }
    }

    /**
     * リソースファイルの内容を追加する。
     * 重複するリソースは上書きされる。
     * @param resourceName
     * @param loader
     */
    public void addResourceFile(String resourceName, ClassLoader loader) {
        try {
            addResourceFile(new ClassLoaderFileLocator(resourceName, loader));
        }
        catch (IllegalArgumentException ex) {
            log.warn("IllegalArgumentException - "+ex.getMessage());
        }
        catch (URISyntaxException ex) {
            log.warn("URISyntaxException - "+ex.getMessage());
        }
    }

    /**
     * リソースファイルの内容を追加する。
     * @param file
     */
    public void addResourceFile(FileLocator file) {
        Resources r = load(file);
        resources.addResources(r);
    }

    private Resources load(FileLocator file) {

        List seq = Util.expandLocale(locale);
        seq.add(Util.NULL_LOCALE);

        // 言語名に、より詳細にマッチするファイルを探す

        Resources ret = null;
        for(int i=0; i<seq.size(); i++) {

            Locale loc = (Locale)seq.get(i);

            // リソースファイルを読み込む

            FileLocator fl = file;

            try {

                // 言語別のファイル名を作る

                if ( !loc.equals(Util.NULL_LOCALE) ) {
                    String filename = StringUtil.makeLocaleFilename(fl.getFilename(), loc);
                    fl = file.newLocation(filename);
                }

                // 読み込み

                if ( fl.exists() ) {
                    ret = ConfigReader.parseResource(fl);
                    break;
                }

            }

            // ロード中に例外がスローされたら別のファイルを読み込んでみる

            catch (ConfigurationIOException ex) {
                log.warn(FileResourceManager.getInstance()
                        .getString("warn.FileResourceManager.ConfigurationIOException", fl.toString(), null, null), ex);
            }

        }

        return ret;

    }

    /**
     * 取得したリソース文字列をパラメータで置き換えるユーティリティメソッド。
     * パラメータ1～3はそれぞれリソース文字列中の"${1}", "${2}", "${3}"と置き換えられる。
     * @param name
     * @return
     */
    public String getString(String name, String param1, String param2, String param3) {
        String ret = getStringResource(name);
        if ( ret != null )
            return StringUtil.replaceParameters(ret, new String[] {param1, param2, param3});
        else
            return null;
    }

    public String getStringResource(String name) {
        return resources.getString(name, null);
    }

}
