/*
 * $Id: Util.java 220 2007-07-16 10:32:15Z sugimotokenichi $
 * Copyright (C) 2004-2005 SUGIMOTO Ken-ichi
 */

package feat2;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletContext;

import org.apache.commons.lang.StringUtils;

import feat2.config.FeatConfig;


public class Util {

    /*public static String getAttribute(NamedNodeMap map, String name, String defaultValue)
            throws FeatException {
        Attr attr = (Attr)map.getNamedItem(name);
        String ret = null;
        if ( attr == null ) {
            if ( defaultValue == null )
                throw new FeatException(name + " == null");
            ret = defaultValue;
        }
        else
            ret = attr.getValue();
        return ret;
    }*/

    public static Throwable getRootCause(Throwable t) {
        while(t.getCause() != null) {
            t = t.getCause();
        }
        return t;
    }

    public static final Locale NULL_LOCALE = new Locale("");

    /**
     * 指定のロケールから類推できるロケールのリストを返す。
     * @param locale
     * @return
     */
    public static List expandLocale(Locale locale) {
        ArrayList list = new ArrayList(3);
        if ( locale != null && !locale.equals(NULL_LOCALE) ) {
            String v = locale.getVariant();
            String c = locale.getCountry();
            String l = locale.getLanguage();
            if ( v.length() > 0 ) {
                list.add(new Locale(l, c, v));
            }
            if ( c.length() > 0 ) {
                list.add(new Locale(l, c));
            }
            if ( l.length() > 0 ) {
                list.add(new Locale(l));
            }
        }
        return list;
    }

    /**
     * ロケール文字列をロケールオブジェクトに変換する。
     * @param localeString
     * @return 渡された文字列が空文字列またはnullのときはnullを返す
     */
    public static Locale parseLocale(String localeString) {
        if ( localeString == null || localeString.length() == 0 )
            return null;

        String[] elem = StringUtils.split(localeString, '_');
        Locale ret = null;
        if ( elem.length == 1 )
            ret = new Locale(elem[0]);
        else if ( elem.length == 2 )
            ret = new Locale(elem[0], elem[1]);
        else if ( elem.length == 3 )
            ret = new Locale(elem[0], elem[1], elem[2]);
        return ret;
    }

    /**
     * ","区切りのリストをパースする。
     * ()の中の','は区切り記号としない。
     * @param list リストの文字列
     * @return 要素が一つも無いときは長さ０の配列
     */
    public static String[] parseList(String list) {
        int len = list.length();
        int mode = MODE_INIT;
        StringBuffer buf = new StringBuffer(16);
        ArrayList ret = new ArrayList();
        int i = 0;
        while ( i < len ) {
            char ch = list.charAt(i++);
            switch(mode) {
                case MODE_INIT:
                    if ( !Character.isWhitespace(ch) ) {
                        mode = MODE_READ;
                        buf.append(ch);
                    }
                    break;

                case MODE_READ:
                    if ( ch == ',') {
                        // ','に遭遇したらリスト値を書き出す
                        String val = buf.toString().trim();
                        if ( val != null && val.length() > 0 )
                            ret.add(val);
                        buf.setLength(0);
                        mode = MODE_INIT;
                    }
                    else {
                        // '('だったらパラメータ読み取りモードへ
                        if ( ch == '(' ) {
                            mode = MODE_FUNCTION_PARAM;
                        }
                        buf.append(ch);
                    }
                    break;

                case MODE_FUNCTION_PARAM:
                    if ( ch == ')' ) {
                        // ')'だったら通常の読み取りモードへ戻る
                        mode = MODE_READ;
                    }
                    buf.append(ch);
                    break;

            }
        }

        // 最後の要素が残っていたら追加
        if ( buf.length() > 0 ) {
            String val = buf.toString().trim();
            if ( val != null && val.length() > 0 )
                ret.add(val);
        }

        return (String[])ret.toArray(new String[ret.size()]);
    }
    private static final int
    MODE_INIT = 0,
    MODE_READ = 1,
    MODE_FUNCTION_PARAM = 2;

    /**
     * 関数形式の文字列を含んだリストをパースする。
     * 関数は、関数名(引数1, 引数2, ... ) の形式。
     * 名前、引数とも前後の空白文字は削除される。
     * @param liststr 関数リスト形式の文字列
     * @return 要素が一つも無いときは長さ０の配列
     * @see Character#isWhitespace(char)
     */
    /*
    public static Function[] parseFunctionList(String liststr) {
        String[] list = parseList(liststr);
        Function[] ret = new Function[list.length];
        for(int i=0; i<list.length; i++) {
            ret[i] = new Function(list[i]);
        }
        return ret;
    }*/

    /**
     * レスポンス名を解析する。
     * @param responseName レスポンス名。"フィーチャー名::レスポンス名"の形式。
     *         フィーチャー名を省略した"レスポンス名"の形式も受け入れる
     * @param featureName responseNameでフィーチャー名が省略されたときのフィーチャー名
     * @return
     */
    /*
    public static ResponsePointer parseResponseName(String responseName, String featureName) {
        ResponsePointer pointer = null;
        if ( responseName.indexOf("::") > -1) {
            String[] elem = StringUtil.split(responseName, "::");
            pointer = new ResponsePointer(elem[0], elem[1]);
        }
        else {
            pointer = new ResponsePointer(featureName, responseName);
        }
        return pointer;
    }*/

    /**
     * featアプリケーションの設定を取得する。
     * @return 設定が取得できなかったらnull
     */
    static FeatConfig getFeatConfig(ServletContext sctx) {
        FeatConfig conf = (FeatConfig)sctx.getAttribute(FeatConst.CONFIG_KEY);
        return conf;
    }

    static void setFeatConfig(ServletContext sctx, FeatConfig config) {
        sctx.setAttribute(FeatConst.CONFIG_KEY, config);
        sctx.setAttribute(FeatConst.CONFIG_LASTUPDATE_KEY, new Long(System.currentTimeMillis()));
    }

    static long getConfigLastUpdateTime(ServletContext sctx) {
        return ((Long)sctx.getAttribute(FeatConst.CONFIG_LASTUPDATE_KEY)).longValue();
    }
}
