package org.maachang.comet.httpd ;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * HTTPD-パラメータ群.
 *
 * @version 2007/08/20
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class HttpdParams {
    
    /**
     * ヘッダ管理.
     */
    private HashMap<String,Object> params = null ;
    
    /**
     * コンストラクタ.
     */
    public HttpdParams() {
        params = new HashMap<String,Object>() ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.params = null ;
    }
    
    /**
     * パラメータオブジェクトをマージ.
     * <BR><BR>
     * 指定オブジェクトをマージします.
     * <BR>
     * @param param 対象のパラメータオブジェクトを設定します.
     */
    public void add( HttpdParams param ) {
        if( param == null || param.size() <= 0 ) {
            return ;
        }
        String[] keys = param.getKeys() ;
        if( keys != null ) {
            int len = keys.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                int lenJ = param.size( keys[ i ] ) ;
                for( int j = 0 ; j < lenJ ; j ++ ) {
                    this.addParam( keys[ i ],param.getParam( keys[ i ],j ) ) ;
                }
            }
        }
    }
    
    /**
     * パラメータ追加.
     * <BR><BR>
     * パラメータを追加します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @param value 対象の要素を設定します.
     */
    public void addParam( String key,Object value ) {
        pushParam( false,key,value ) ;
    }
    
    /**
     * パラメータ設定.
     * <BR><BR>
     * パラメータを設定します.<BR>
     * この条件で設定した場合、以前に登録したkeyに
     * 対する内容はクリアされます.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @param value 対象の要素を設定します.
     */
    public void setParam( String key,Object value ) {
        pushParam( true,key,value ) ;
    }
    
    /**
     * パラメータを追加／設定.
     * mode[true]の場合は、パラメータ設定.
     */
    private void pushParam( boolean mode,String key,Object value ) {
        if( key == null ) {
            return ;
        }
        if( value == null ) {
            value = "" ;
        }
        else if( ( value instanceof String || value instanceof HttpdBinary ) == false ) {
            return ;
        }
        if( mode == true ) {
            params.put( key,value ) ;
        }
        else {
            if( params.containsKey( key ) == false ) {
                params.put( key,value ) ;
            }
            else {
                ArrayList<Object> lst = null ;
                Object v = params.get( key ) ;
                if( v instanceof ArrayList ) {
                    lst = ( ArrayList<Object> )v ;
                }
                else {
                    lst = new ArrayList<Object>() ;
                    lst.add( v ) ;
                    params.put( key,lst ) ;
                }
                lst.add( value ) ;
            }
        }
    }
    
    /**
     * パラメータを削除.
     * <BR><BR>
     * 対象のパラメータを削除します.
     * <BR>
     * @param key 対象のキー名を設定します.
     */
    public void removeParam( String key ) {
        if( key == null || params == null ) {
            return ;
        }
        params.remove( key ) ;
    }
    
    /**
     * パラメータを削除.
     * <BR><BR>
     * 対象のパラメータを削除します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @param no 対象の項番を設定します.
     */
    public void removeParam( String key,int no ) {
        if( key == null || params == null || no < 0 ) {
            return ;
        }
        int len = getKeyByLength( key ) ;
        if( len <= 0 || no >= len ) {
            return ;
        }
        if( len == 1 ) {
            params.remove( key ) ;
        }
        else {
            ArrayList v = ( ArrayList )params.get( key ) ;
            v.remove( no ) ;
        }
    }
    
    /**
     * パラメータを取得.
     * <BR><BR>
     * 対象のパラメータを取得します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @return Object 対象の要素情報が返されます.
     */
    public String getParam( String key ) {
        return getParam( key,0 ) ;
    }
    
    /**
     * パラメータを取得.
     * <BR><BR>
     * 対象のパラメータを取得します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @param no 対象の項番を設定します.
     * @return Object 対象の要素情報が返されます.
     */
    public String getParam( String key,int no ) {
        if( key == null || params == null || no < 0 ) {
            return null ;
        }
        int len = getKeyByLength( key ) ;
        if( len <= 0 || no >= len ) {
            return null ;
        }
        Object v = params.get( key ) ;
        if( v instanceof ArrayList ) {
            v = ( ( ArrayList )v ).get( no ) ;
        }
        if( v instanceof String ) {
            return ( String )v ;
        }
        return v.toString() ;
    }
    
    /**
     * パラメータをバイナリオブジェクトとして取得.
     * <BR><BR>
     * 対象のパラメータをバイナリオブジェクトとして取得します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @return HttpdBinary 対象の要素情報が返されます.
     */
    public HttpdBinary getParamByBinary( String key ) {
        return getParamByBinary( key,0 ) ;
    }
    
    /**
     * パラメータをバイナリオブジェクトとして取得.
     * <BR><BR>
     * 対象のパラメータをバイナリオブジェクトとして取得します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @param no 対象の項番を設定します.
     * @return HttpdBinary 対象の要素情報が返されます.
     */
    public HttpdBinary getParamByBinary( String key,int no ) {
        if( key == null || params == null || no < 0 ) {
            return null ;
        }
        int len = getKeyByLength( key ) ;
        if( len <= 0 || no >= len ) {
            return null ;
        }
        Object v = params.get( key ) ;
        if( v instanceof ArrayList ) {
            v = ( ( ArrayList )v ).get( no ) ;
        }
        if( v instanceof String ) {
            HttpdBinary b = null ;
            try {
                b = new HttpdBinary( key,"text/plain",( ( String )v ).getBytes( "UTF8" ) ) ;
            } catch( Exception e ) {
                b = null ;
            }
            return b ;
        }
        return ( HttpdBinary )v ;
    }
    
    /**
     * パラメータタイプを取得.
     * <BR><BR>
     * パラメータタイプを取得します.
     * <BR>
     * @param key 対象のパラメータキー名を設定します.
     * @return boolean 対象のパラメータタイプが返されます.<BR>
     *                 [true]の場合は、バイナリタイプです.<BR>
     *                 [false]の場合は、文字タイプです.
     */
    public boolean getParamType( String key ) {
        return getParamType( key,0 ) ;
    }
    
    /**
     * パラメータタイプを取得.
     * <BR><BR>
     * パラメータタイプを取得します.
     * <BR>
     * @param key 対象のパラメータキー名を設定します.
     * @param no 対象の項番を設定します.
     * @return boolean 対象のパラメータタイプが返されます.<BR>
     *                 [true]の場合は、バイナリタイプです.<BR>
     *                 [false]の場合は、文字タイプです.
     */
    public boolean getParamType( String key,int no ) {
        if( key == null || params == null || no < 0 ) {
            return false ;
        }
        int len = getKeyByLength( key ) ;
        if( len <= 0 || no >= len ) {
            return false ;
        }
        Object v = params.get( key ) ;
        if( v instanceof ArrayList ) {
            v = ( ( ArrayList )v ).get( no ) ;
        }
        if( v instanceof String ) {
            return false ;
        }
        return true ;
    }
    
    /**
     * パラメータ数を取得.
     * <BR><BR>
     * 対象のパラメータ数を取得します.
     * <BR>
     * @return int パラメータ数が返されます.
     */
    public int size() {
        return ( params == null ) ? 0 : params.size() ;
    }
    
    /**
     * パラメータ数を取得.
     * <BR><BR>
     * 対象のパラメータ数を取得します.
     * <BR>
     * @param key 対象のキー名を設定します.
     * @return int パラメータ数が返されます.
     */
    public int size( String key ) {
        if( key == null || params == null ) {
            return 0 ;
        }
        return getKeyByLength( key ) ;
    }
    
    /**
     * キー名群を取得.
     * <BR><BR>
     * 対象のキー名群を取得します.
     * <BR>
     * @return String[] キー名群が返されます.
     */
    public String[] getKeys() {
        if( params == null || params.size() <= 0 ) {
            return null ;
        }
        Object[] keys = params.keySet().toArray() ;
        if( keys != null ) {
            int len = keys.length ;
            String[] ret = new String[ len ] ;
            for( int i = 0 ; i < len ; i ++ ) {
                ret[ i ] = ( String )keys[ i ] ;
            }
            return ret ;
        }
        return null ;
    }
    
    /**
     * 指定キーが存在するかチェック.
     * <BR><BR>
     * 指定キーが存在するかチェックします.
     * <BR>
     * @param key 対象のキー名を取得します.
     * @return boolean [true]の場合、存在します.
     */
    public boolean isKey( String key ) {
        if( params == null ) {
            return false ;
        }
        return params.containsKey( key ) ;
    }
    
    /**
     * 管理パラメータを取得.
     * <BR><BR>
     * このオブジェクトが管理しているパラメータを取得します.
     * <BR>
     * @return HashMap<String,Object> 管理パラメータが返されます.
     */
    public HashMap<String,Object> getPrivateMap() {
        return params ;
    }
    
    /**
     * 文字列に変換.
     */
    public String toString() {
        String[] keys = getKeys() ;
        if( keys != null ) {
            StringBuilder buf = new StringBuilder() ;
            int len = keys.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                if( i != 0 ) {
                    buf.append( "," ) ;
                }
                Object v = params.get( keys[ i ] ) ;
                if( v instanceof ArrayList ) {
                    ArrayList<Object> lst = ( ArrayList<Object> )v ;
                    if( lst != null ) {
                        int lenJ = lst.size() ;
                        for( int j = 0 ; j < lenJ ; j ++ ) {
                            if( j != 0 ) {
                                buf.append( "," ) ;
                            }
                            Object objs = lst.get( j ) ;
                            buf.append( " [" ).
                                append( keys[ i ] ).
                                append( ":" ) ;
                            if( objs instanceof String ) {
                                buf.append( objs ).append( "]" ) ;
                            }
                            else if( objs instanceof HttpdBinary ) {
                                buf.append( " orginal/" ).
                                    append( ( ( HttpdBinary )objs ).getOriginalName() ).
                                    append( " length/" ).
                                    append( ( ( HttpdBinary )objs ).getLength() ).
                                    append( "]" ) ;
                            }
                        }
                    }
                }
                else {
                    buf.append( " [" ).
                        append( keys[ i ] ).
                        append( ":" ) ;
                    if( v instanceof String ) {
                        buf.append( v ).append( "]" ) ;
                    }
                    else if( v instanceof HttpdBinary ) {
                        buf.append( " orginal/" ).
                            append( ( ( HttpdBinary )v ).getOriginalName() ).
                            append( " length/" ).
                            append( ( ( HttpdBinary )v ).getLength() ).
                            append( "]" ) ;
                    }
                }
            }
            return buf.toString() ;
        }
        else {
            return "null" ;
        }
    }
    
    /**
     * 指定名のサイズを取得.
     */
    private int getKeyByLength( String key ) {
        if( key == null || key.length() <= 0 ) {
            return 0 ;
        }
        if( params.containsKey( key ) == false ) {
            return 0 ;
        }
        Object v = params.get( key ) ;
        if( v instanceof ArrayList ) {
            return ( ( ArrayList )v ).size() ;
        }
        return 1 ;
    }
}

