package org.maachang.conf;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Iniパラメータ管理.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangBase 1.00
 */
public class Config {

    /**
     * パラメータ管理.
     */
    private HashMap<String, HashMap<String, ArrayList<String>>> params = new HashMap<String, HashMap<String, ArrayList<String>>>();

    /**
     * パラメータキー位置格納.
     */
    private HashMap<String, ArrayList<String>> keyByNum = new HashMap<String, ArrayList<String>>() ;
    
    /**
     * コンフィグファイルを読み込み.
     * @param name 対象のファイル名を呼び出します.
     * @return Config コンフィグ情報が返されます.
     * @exception Exception 例外.
     */
    public static final Config read( String name ) throws Exception {
        Config ret = new Config() ;
        ReadConfigUtil.readConfig( ret,name ) ;
        return ret ;
    }

    /**
     * コンストラクタ.
     */
    public Config() {

    }

    /**
     * 情報クリア. <BR>
     * <BR>
     * 情報をクリアします.
     */
    public synchronized void clear() {
        params.clear();
        keyByNum.clear();
    }

    /**
     * 新しいパラメータを追加. <BR>
     * <BR>
     * 新しいパラメータを追加します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param value
     *            対象の要素を追加します.
     */
    public synchronized void put(String section, String key, String value) {
        if (section == null || key == null) {
            return;
        }
        if (value == null) {
            value = "";
        }
        section = section.trim();
        key = key.trim();
        ArrayList<String> keys = keyByNum.get(section);
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue == null) {
            sectionValue = new HashMap<String, ArrayList<String>>();
            params.put(section, sectionValue);
            keys = new ArrayList<String>() ;
            keyByNum.put(section, keys);
        }
        ArrayList<String> keyValue = sectionValue.get(key);
        if (keyValue == null) {
            keyValue = new ArrayList<String>();
            sectionValue.put(key, keyValue);
            keys.add(key);
        }
        keyValue.add(value);
    }

    /**
     * 新しいパラメータを設定. <BR>
     * <BR>
     * 新しいパラメータを設定します. <BR>
     * この条件の場合、既に同一条件が存在する場合、上書きします.
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param value
     *            対象の要素を追加します.
     */
    public synchronized void set(String section, String key, String value) {
        if (section == null || key == null) {
            return;
        }
        if (value == null) {
            value = "";
        }
        section = section.trim();
        key = key.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue == null) {
            sectionValue = new HashMap<String, ArrayList<String>>();
            params.put(section, sectionValue);
        }
        ArrayList<String> keyValue = sectionValue.get(key);
        if (keyValue == null) {
            keyValue = new ArrayList<String>();
            sectionValue.put(key, keyValue);
        }
        else {
            keyValue.clear() ;
        }
        keyValue.add(value);
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return String 対象の要素が返されます.
     */
    public synchronized String get(String section, String key, int no) {
        if (section == null || key == null || no < 0) {
            return null;
        }
        section = section.trim();
        key = key.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            ArrayList<String> value = sectionValue.get(key);
            if (value != null) {
                if (value.size() > no) {
                    return value.get(no);
                }
            }
        }
        return null;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return boolean 対象の要素が返されます.
     */
    public synchronized boolean getBoolean(String section, String key, int no) {
        return ConvIniParam.getBoolean( get( section,key,no ) ) ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return Boolean 対象の要素が返されます.
     */
    public synchronized Boolean getBooleanObject(String section, String key, int no) {
        Boolean ret = null ;
        String s = get( section,key,no ) ;
        if( s != null ) {
            try {
                ret = new Boolean( s ) ;
            } catch( Exception e ) {
                ret = null ;
            }
        }
        return ret ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return int 対象の要素が返されます.
     */
    public synchronized int getInt(String section, String key, int no) {
        return ConvIniParam.getInt( get( section,key,no ) ) ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return Integer 対象の要素が返されます.
     */
    public synchronized Integer getIntObject(String section, String key, int no) {
        Integer ret = null ;
        String s = get( section,key,no ) ;
        if( s != null ) {
            try {
                ret = new Integer( s ) ;
            } catch( Exception e ) {
                ret = null ;
            }
        }
        return ret ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return long 対象の要素が返されます.
     */
    public synchronized long getLong(String section, String key, int no) {
        return ConvIniParam.getLong( get( section,key,no ) ) ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return Long 対象の要素が返されます.
     */
    public synchronized Long getLongObject(String section, String key, int no) {
        Long ret = null ;
        String s = get( section,key,no ) ;
        if( s != null ) {
            try {
                ret = new Long( s ) ;
            } catch( Exception e ) {
                ret = null ;
            }
        }
        return ret ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return double 対象の要素が返されます.
     */
    public synchronized double getDouble(String section, String key, int no) {
        return ConvIniParam.getDouble( get( section,key,no ) ) ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return Double 対象の要素が返されます.
     */
    public synchronized Double getDoubleObject(String section, String key, int no) {
        Double ret = null ;
        String s = get( section,key,no ) ;
        if( s != null ) {
            try {
                ret = new Double( s ) ;
            } catch( Exception e ) {
                ret = null ;
            }
        }
        return ret ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return InetAddress 対象の要素が返されます.
     */
    public synchronized InetAddress getInetAddress(String section, String key, int no) {
        return ConvIniParam.getInetAddress( get( section,key,no ) ) ;
    }

    /**
     * 指定要素の内容を取得. <BR>
     * <BR>
     * 指定要素の内容を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @param no
     *            対象の項番を設定します.
     * @return String[] 対象の要素群が返されます.
     */
    public synchronized String[] getAll(String section, String key) {
        if (section == null || key == null) {
            return null;
        }
        section = section.trim();
        key = key.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            ArrayList<String> value = sectionValue.get(key);
            if (value != null && value.size() > 0) {
                int len = value.size();
                String[] ret = new String[len];
                for (int i = 0; i < len; i++) {
                    ret[i] = value.get(i);
                }
                return ret;
            }
        }
        return null;
    }

    /**
     * 指定セクションを削除. <BR>
     * <BR>
     * 指定セクションを削除します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     */
    public synchronized void removeSection(String section) {
        if (section == null) {
            return;
        }
        params.remove(section);
        keyByNum.remove(section) ;
    }

    /**
     * 指定キー情報を削除. <BR>
     * <BR>
     * 指定キー情報を削除します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     */
    public synchronized void removeKey(String section,String key) {
        if (section == null || key == null) {
            return;
        }
        section = section.trim();
        key = key.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            sectionValue.remove(key) ;
            ArrayList<String> keys = keyByNum.get(section);
            if( keys != null && keys.size() > 0 ) {
                int len = keys.size() ;
                for( int i = 0 ; i < len ; i ++ ) {
                    if( key.equals( keys.get( i ) ) ) {
                        keys.remove( i ) ;
                        break ;
                    }
                }
            }
        }
    }

    /**
     * 指定要素数を取得. <BR>
     * <BR>
     * 指定要素数を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @return int 指定要素数が返されます.
     */
    public synchronized int size(String section, String key) {
        if (section == null || key == null) {
            return -1;
        }
        section = section.trim();
        key = key.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            ArrayList<String> value = sectionValue.get(key);
            if (value != null) {
                return value.size();
            }
        }
        return -1;
    }

    /**
     * 指定キー数を取得. <BR>
     * <BR>
     * 指定キー数を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @return int 指定キー数が返されます.
     */
    public synchronized int size(String section) {
        if (section == null) {
            return -1;
        }
        section = section.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            return sectionValue.size() ;
        }
        return -1;
    }

    /**
     * 指定セクション数を取得. <BR>
     * <BR>
     * 指定セクション数が返されます. <BR>
     * 
     * @return int セクション数が返されます.
     */
    public synchronized int size() {
        return params.size();
    }

    /**
     * 指定キー群を取得. <BR>
     * <BR>
     * 指定キー群を取得します. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @return String[] 指定キー群が返されます.
     */
    public synchronized String[] getKeys(String section) {
        if (section == null) {
            return null;
        }
        section = section.trim();
        ArrayList<String> keys = keyByNum.get(section);
        String[] ret = null ;
        if( keys != null && keys.size() > 0 ) {
            int len = keys.size() ;
            ret = new String[ len ] ;
            for( int i = 0 ; i < len ; i ++ ) {
                ret[ i ] = keys.get( i ) ;
            }
        }
        return ret ;
    }

    /**
     * セクション名一覧を取得. <BR>
     * <BR>
     * セクション名一覧を取得します. <BR>
     * 
     * @return Object[] セクション名一覧が返されます.
     */
    public synchronized Object[] getSections() {
        if (params != null && params.size() > 0) {
            return params.keySet().toArray();
        }
        return null;
    }

    /**
     * 指定キー名が存在するかチェック. <BR>
     * <BR>
     * 指定キー名が存在するかチェックします. <BR>
     * 
     * @param section
     *            対象のセクション名を設定します.
     * @param key
     *            対象のキー名を設定します.
     * @return boolean [true]の場合は存在します.
     */
    public synchronized boolean isKeys(String section,String key) {
        if (section == null) {
            return false;
        }
        section = section.trim();
        HashMap<String, ArrayList<String>> sectionValue = params.get(section);
        if (sectionValue != null) {
            return ( sectionValue.get( key ) != null ) ? true : false ;
        }
        return false;
    }

    /**
     * セクション名が存在するかチェック.
     * <BR><BR>
     * セクション名が存在するかチェックします.
     * <BR>
     * @param name セクション名を設定します.
     * @return boolean [true]の場合は存在します.
     */
    public synchronized boolean isSection( String section ) {
        section = section.trim();
        return ( params.get( section ) != null ) ? true : false ;
    }

    /**
     * 文字列に変換.
     */
    public synchronized String toString() {
        if (params != null && params.size() > 0) {
            StringBuilder buf = new StringBuilder();
            Object[] objs = params.keySet().toArray();
            int len = objs.length;
            for (int i = 0; i < len; i++) {
                buf.append("[").append(objs[i]).append("]\n");
                HashMap<String, ArrayList<String>> key = params.get(objs[i]);
                if (key != null && key.size() > 0) {
                    Object[] sObjs = key.keySet().toArray();
                    int lenJ = sObjs.length;
                    for (int j = 0; j < lenJ; j++) {
                        buf.append("  ").append(sObjs[j]).append("\n");
                        ArrayList<String> emt = key.get(sObjs[j]);
                        if (emt != null && emt.size() > 0) {
                            int lenK = emt.size();
                            buf.append("    ");
                            for (int k = 0; k < lenK; k++) {
                                if (k != 0) {
                                    buf.append(",");
                                }
                                buf.append(emt.get(k));
                            }
                            buf.append("\n");
                        }
                    }
                }
            }
            return buf.toString();
        }
        return "null";
    }
}

