package org.maachang.bdb ;

import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Bdb アクセス用オブジェクト.
 * 
 * @version 2010/01/05
 * @author masahito suzuki
 * @since Bdb 1.00
 */
public abstract class AccessBdb {
    
    /**
     * 取得データタイプ : バイナリ.
     */
    public static final int TYPE_BINARY = 0 ;
    
    /**
     * 取得データタイプ : 文字列.
     */
    public static final int TYPE_STRING = 1 ;
    
    /**
     * 取得データタイプ : short.
     */
    public static final int TYPE_SHORT = 2 ;
    
    /**
     * 取得データタイプ : int.
     */
    public static final int TYPE_INT = 3 ;
    
    /**
     * 取得データタイプ : long.
     */
    public static final int TYPE_LONG = 4 ;
    
    /**
     * 取得データタイプ : float.
     */
    public static final int TYPE_FLOAT = 5 ;
    
    /**
     * 取得データタイプ : double.
     */
    public static final int TYPE_DOUBLE = 6 ;
    
    /**
     * 取得データタイプ : bigDecimal.
     */
    public static final int TYPE_DECIMAL = 7 ;
    
    /**
     * 取得データタイプ : シリアライズされたオブジェクト.
     */
    public static final int TYPE_OBJECT = 8 ;
    
    /** プリミティブ変換Map **/
    protected static final Map<Class,Integer> cnvMap ;
    /** プリミティブ非変換Map **/
    protected static final Set<Class> ncnvSet ;
    static {
        Map<Class,Integer> m = new HashMap<Class,Integer>() ;
        m.put( java.lang.Short.class,2 ) ;
        m.put( java.lang.Integer.class,3 ) ;
        m.put( java.lang.Long.class,4 ) ;
        m.put( java.lang.Float.class,5 ) ;
        m.put( java.lang.Double.class,6) ;
        m.put( java.lang.Short.TYPE,2 ) ;
        m.put( java.lang.Integer.TYPE,3 ) ;
        m.put( java.lang.Long.TYPE,4 ) ;
        m.put( java.lang.Float.TYPE,5 ) ;
        m.put( java.lang.Double.TYPE,6) ;
        cnvMap = m ;
        Set<Class> n = new HashSet<Class>() ;
        n.add( java.lang.Boolean.class ) ;
        n.add( java.lang.Byte.class ) ;
        n.add( java.lang.Character.class ) ;
        n.add( java.lang.Boolean.TYPE ) ;
        n.add( java.lang.Byte.TYPE ) ;
        n.add( java.lang.Character.TYPE ) ;
        ncnvSet = n ;
    }
    
    /**
     * コンストラクタ.
     */
    private AccessBdb() {
        
    }
    
    /**
     * 情報を設定.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @param value 対象の情報を設定します.
     * @exception Exception 例外.
     */
    public static void put( Bdb bdb,BdbKeyValue kv,byte[] key,Object value ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length <= 0 || value == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        bdb.put( kv.create( key,cbin( value ) ) ) ;
    }
    
    /**
     * 情報を設定.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @param value 対象の情報を設定します.
     * @exception Exception 例外.
     */
    public static void put( Bdb bdb,BdbKeyValue kv,String key,Object value ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length() <= 0 || value == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        bdb.put( kv.create( key.getBytes( "UTF8" ),cbin( value ) ) ) ;
    }
    
    /**
     * 情報を設定.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @param value 対象の情報を設定します.
     * @exception Exception 例外.
     */
    public static void put( Bdb bdb,BdbKeyValue kv,short key,Object value ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( value == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        bdb.put( kv.create( ConvertParam.convertShort( key ),cbin( value ) ) ) ;
    }
    
    /**
     * 情報を設定.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @param value 対象の情報を設定します.
     * @exception Exception 例外.
     */
    public static void put( Bdb bdb,BdbKeyValue kv,int key,Object value ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( value == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        bdb.put( kv.create( ConvertParam.convertInt( key ),cbin( value ) ) ) ;
    }
    
    /**
     * 情報を削除.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return boolean [true]の場合、削除できました.
     * @exception Exception 例外.
     */
    public static boolean remove( Bdb bdb,BdbKeyValue kv,byte[] key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        return bdb.remove( kv.setKey( key ) ) ;
    }
    
    /**
     * 情報を削除.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return boolean [true]の場合、削除できました.
     * @exception Exception 例外.
     */
    public static boolean remove( Bdb bdb,BdbKeyValue kv,String key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        return bdb.remove( kv.setKey( key.getBytes( "UTF8" ) ) ) ;
    }
    
    /**
     * 情報を削除.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return boolean [true]の場合、削除できました.
     * @exception Exception 例外.
     */
    public static boolean remove( Bdb bdb,BdbKeyValue kv,short key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        return bdb.remove( kv.setKey( ConvertParam.convertShort( key ) ) ) ;
    }
    
    /**
     * 情報を削除.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return boolean [true]の場合、削除できました.
     * @exception Exception 例外.
     */
    public static boolean remove( Bdb bdb,BdbKeyValue kv,int key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        return bdb.remove( kv.setKey( ConvertParam.convertInt( key ) ) ) ;
    }
    
    /**
     * 情報を削除.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return boolean [true]の場合、削除できました.
     * @exception Exception 例外.
     */
    public static boolean remove( Bdb bdb,BdbKeyValue kv,long key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        return bdb.remove( kv.setKey( ConvertParam.convertLong( key ) ) ) ;
    }
    
    /**
     * 情報を取得.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return Object 対象の情報が返されます.
     * @exception Exception 例外.
     */
    public static Object get( Bdb bdb,BdbKeyValue kv,int type,byte[] key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( bdb.get( kv.setKey( key ) ) ) {
            return dbin( type,kv.getValue() ) ;
        }
        return null ;
    }
    
    /**
     * 情報を取得.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return Object 対象の情報が返されます.
     * @exception Exception 例外.
     */
    public static Object get( Bdb bdb,BdbKeyValue kv,int type,String key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( key == null || key.length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( bdb.get( kv.setKey( key.getBytes( "UTF8" ) ) ) ) {
            return dbin( type,kv.getValue() ) ;
        }
        return null ;
    }
    
    /**
     * 情報を取得.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return Object 対象の情報が返されます.
     * @exception Exception 例外.
     */
    public static Object get( Bdb bdb,BdbKeyValue kv,int type,short key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( bdb.get( kv.setKey( ConvertParam.convertShort( key ) ) ) ) {
            return dbin( type,kv.getValue() ) ;
        }
        return null ;
    }
    
    /**
     * 情報を取得.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return Object 対象の情報が返されます.
     * @exception Exception 例外.
     */
    public static Object get( Bdb bdb,BdbKeyValue kv,int type,int key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( bdb.get( kv.setKey( ConvertParam.convertInt( key ) ) ) ) {
            return dbin( type,kv.getValue() ) ;
        }
        return null ;
    }
    
    /**
     * 情報を取得.
     * @param bdb 実行対象のBdbオブジェクトが返されます.
     * @param kv KeyValue格納オブジェクトを設定します.
     * @param key 対象のキー情報を設定します.
     * @return Object 対象の情報が返されます.
     * @exception Exception 例外.
     */
    public static Object get( Bdb bdb,BdbKeyValue kv,int type,long key ) throws Exception {
        if( bdb == null || bdb.isClose() ) {
            throw new IllegalArgumentException( "指定されたBdbオブジェクトは利用できません" ) ;
        }
        if( kv == null ) {
            kv = BdbManager.getBdbKeyValue() ;
        }
        if( bdb.get( kv.setKey( ConvertParam.convertLong( key ) ) ) ) {
            return dbin( type,kv.getValue() ) ;
        }
        return null ;
    }
    
    /**
     * バイナリ変換.
     */
    private static final byte[] cbin( Object v ) throws Exception {
        if( v == null ) {
            throw new IllegalArgumentException( "指定引数はnullです" ) ;
        }
        if( ncnvSet.contains( v ) ) {
            throw new IOException( "指定要素は変換できない型式です:"+v.getClass().getName() ) ;
        }
        int type = cnvMap.get( v.getClass() ) ;
        switch( type ) {
            case TYPE_SHORT : return ConvertParam.convertShort( ((Short)v) ) ;
            case TYPE_INT : return ConvertParam.convertInt( ((Integer)v) ) ;
            case TYPE_LONG : return ConvertParam.convertLong( ((Long)v) ) ;
            case TYPE_FLOAT : return ConvertParam.convertFloat( ((Float)v) ) ;
            case TYPE_DOUBLE : return ConvertParam.convertDouble( ((Double)v) ) ;
        }
        if( v instanceof byte[] ) {
            return (byte[])v ;
        }
        if( v instanceof String ) {
            return ((String)v).getBytes( "UTF8" ) ;
        }
        if( v instanceof BigDecimal ) {
            return ConvertParam.convertDecimal( (BigDecimal)v ) ;
        }
        if( v instanceof Serializable ) {
            return SerializableUtil.toBinary( (Serializable)v ) ;
        }
        throw new IOException( "指定要素は変換できない型式です:"+v.getClass().getName() ) ;
    }
    
    /**
     * 取得バイナリを指定条件に変換.
     */
    private static final Object dbin( int type,byte[] v ) throws Exception {
        if( v == null || v.length <= 0 ) {
            throw new IllegalArgumentException( "指定引数はnullです" ) ;
        }
        switch( type ) {
            case TYPE_BINARY : return v ;
            case TYPE_STRING : return new String( v,"UTF8" ) ;
            case TYPE_SHORT : return ConvertParam.convertShort( 0,v ) ;
            case TYPE_INT : return ConvertParam.convertInt( 0,v ) ;
            case TYPE_LONG : return ConvertParam.convertLong( 0,v ) ;
            case TYPE_FLOAT : return ConvertParam.convertFloat( 0,v ) ;
            case TYPE_DOUBLE : return ConvertParam.convertDouble( 0,v ) ;
            case TYPE_DECIMAL : return ConvertParam.convertDecimal( 0,v ) ;
            case TYPE_OBJECT : return SerializableUtil.toObject( v ) ;
        }
        return v ;
    }
}
