package org.maachang.mimdb.core;

import org.maachang.mimdb.core.util.NNObjectKeyValue;
import org.maachang.mimdb.core.util.NumberKeySet;
import org.maachang.mimdb.core.util.ObjectBinary;

/**
 * Remote用テーブル情報.
 * サーバー接続モードでのクライアントが認識している
 * テーブル情報.
 * 
 * @version 2014/01/17
 * @author masahito suzuki
 * @since MasterInMemDB 1.02
 */
public class RemoteTable implements BaseTable {
    
    /** DB更新ID. **/
    protected long dbId = -1 ;
    
    /** テーブル名. **/
    protected String name = null ;
    
    /** カラム名一覧. **/
    protected String[] columns = null ;
    
    /** カラム型定義. **/
    protected int[] types = null ;
    
    /** カラム数. **/
    protected int columnLength = 0 ;
    
    /** カラム名Map. **/
    protected NNObjectKeyValue<String,Integer> columnsMap = null ;
    
    /** インデックス項番. **/
    protected NumberKeySet indexs = null ;
    
    /** 最終更新時間. **/
    protected long lastUpdateTime = System.currentTimeMillis() ;
    
    /**
     * コンストラクタ.
     */
    public RemoteTable() {}
    
    /**
     * コンストラクタ.
     * @parma dbId 対象の更新IDを設定します.
     * @param name 対象のテーブル名を設定します.
     * @param columns 対象のカラム名一覧が設定されます.
     * @param types 対象のカラムタイプ一覧が設定されます.
     * @param indexs 対象のインデックスカラム項番が設定されます.
     */
    public RemoteTable( long dbId,String name,String[] columns,int[] types,int[] indexs ) {
        create( dbId,name,columns,types,indexs ) ;
    }
    
    /**
     * 情報生成.
     * @parma dbId 対象の更新IDを設定します.
     * @param name 対象のテーブル名を設定します.
     * @param columns 対象のカラム名一覧が設定されます.
     * @param types 対象のカラムタイプ一覧が設定されます.
     * @param indexs 対象のインデックスカラム項番が設定されます.
     */
    public void create( long dbId,String name,String[] columns,int[] types,int[] indexs ) {
        NNObjectKeyValue<String,Integer> map = new NNObjectKeyValue<String,Integer>() ;
        NumberKeySet idx = new NumberKeySet() ;
        
        int len = columns.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            map.put( columns[ i ],i ) ;
        }
        len = indexs.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            idx.add( indexs[ i ] ) ;
        }
        
        this.dbId = dbId ;
        this.name = name ;
        this.columns = columns ;
        this.types = types ;
        this.columnLength = columns.length ;
        this.columnsMap = map ;
        this.indexs = idx ;
    }
    
    /**
     * 情報クリア.
     */
    public void clear() {
        dbId = -1 ;
        name = null ;
        columns = null ;
        types = null ;
        columnLength = 0 ;
        columnsMap = null ;
        indexs = null ;
    }
    
    /**
     * オブジェクトをバイナリから生成.
     * @param out 書き込み対象のオブジェクトを設定します.
     * @param b 対象のバイナリ情報を設定します.
     * @param off 対象のオフセット値を設定します.
     * @param len 対象の長さを設定します.
     * @return int 読み込んだ情報分のオフセット値が返却されます.
     * @exception Exception 例外.
     */
    public static final int toObject( RemoteTable out,byte[] b,int off,int len )
        throws Exception {
        out.clear() ;
        
        int[] p = new int[]{ off } ;
        
        // テーブル名を取得.
        String name = (String)ObjectBinary.decodeBinary( p,b,len ) ;
        
        // 更新IDを取得.
        long dbId = (Long)ObjectBinary.decodeBinary( p,b,len ) ;
        
        // カラム名をセット.
        String[] columns = (String[])ObjectBinary.decodeBinary( p,b,len ) ;
        
        // カラムタイプをセット.
        int[] types = (int[])ObjectBinary.decodeBinary( p,b,len ) ;
        
        // インデックスIDをセット.
        int[] indexs = (int[])ObjectBinary.decodeBinary( p,b,len ) ;
        
        // オブジェクト生成.
        out.create( dbId,name,columns,types,indexs ) ;
        out.update() ;
        
        return p[ 0 ] ;
    }
    
    /**
     * DB更新IDを取得.
     * この情報が、結果データと一致しない場合は、その結果データは古くなっています.
     * @return int DB更新IDが返却されます.
     */
    public long getDbId() {
        return dbId ;
    }
    
    /**
     * テーブル名を取得.
     * @return String テーブル名が返却されます.
     */
    public String getName() {
        return name ;
    }
    
    /**
     * カラム数の取得.
     * @return int カラム数が返却されます.
     */
    public int getColumnSize() {
        return columnLength ;
    }
    
    /**
     * カラム名を取得.
     * @param no カラム項番を設定します.
     * @return String カラム名が返却されます.
     */
    public String getColumnName( int no ) {
        if( no < 0 || no >= columnLength ) {
            return null ;
        }
        return columns[ no ] ;
    }
    
    /**
     * 指定カラム名に対する項番を取得.
     * @param name カラム名を設定します.
     * @return int カラム項番が返却されます.
     *             [-1]の場合は対象カラム名は存在しません.
     */
    public int getColumnNameByNo( String name ) {
        if( columnsMap.containsKey( name ) ) {
            return columnsMap.get( name ) ;
        }
        return -1 ;
    }
    
    /**
     * カラムタイプを取得.
     * @param no カラム項番を設定します.
     * @return int カラムタイプが返却されます.
     *             -1が返却された場合は、対象カラムは存在しません.
     * java.lang.Boolean  : MimdbIndex.COLUMN_BOOL
     * java.lang.Integer  : MimdbIndex.COLUMN_INT
     * java.lang.Long     : MimdbIndex.COLUMN_LONG
     * java.lang.Double   : MimdbIndex.COLUMN_FLOAT
     * java.lang.String   : MimdbIndex.COLUMN_STRING
     * java.sql.Date      : MimdbIndex.COLUMN_DATE
     * java.sql.Time      : MimdbIndex.COLUMN_TIME
     * java.sql.Timestamp : MimdbIndex.COLUMN_TIMESTAMP
     * java.util.Date     : MimdbIndex.COLUMN_DATE
     */
    public int getColumnType( int no ) {
        if( no < 0 || no >= columnLength ) {
            return -1 ;
        }
        return types[ no ] ;
    }
    
    /**
     * カラムタイプを取得.
     * @param name 対象のカラム名を設定します.
     * @return int カラムタイプが返却されます.
     *             -1が返却された場合は、対象カラムは存在しません.
     * java.lang.Boolean  : MimdbIndex.COLUMN_BOOL
     * java.lang.Integer  : MimdbIndex.COLUMN_INT
     * java.lang.Long     : MimdbIndex.COLUMN_LONG
     * java.lang.Double   : MimdbIndex.COLUMN_FLOAT
     * java.lang.String   : MimdbIndex.COLUMN_STRING
     * java.sql.Date      : MimdbIndex.COLUMN_DATE
     * java.sql.Time      : MimdbIndex.COLUMN_TIME
     * java.sql.Timestamp : MimdbIndex.COLUMN_TIMESTAMP
     * java.util.Date     : MimdbIndex.COLUMN_DATE
     */
    public int getColumnType( String name ) {
        if( columnsMap.containsKey( name ) ) {
            return types[ columnsMap.get( name ) ] ;
        }
        return -1 ;
    }
    
    /**
     * 指定項番のカラムがインデックスかチェック.
     * @param no 対象のカラム項番を設定します.
     * @return boolean [true]の場合は、インデックスです.
     */
    public boolean isIndex( int no ) {
        return indexs.contains( no ) ;
    }
    
    /**
     * 指定項番のカラムがインデックスかチェック.
     * @param name 対象のカラム名を設定します.
     * @return boolean [true]の場合は、インデックスです.
     */
    public boolean isIndex( String name ) {
        if( columnsMap.containsKey( name ) ) {
            return indexs.contains( columnsMap.get( name ) ) ;
        }
        return false ;
    }
    
    /**
     * カラム名一覧を取得.
     * @return String[] カラム名一覧が返却されます.
     */
    public String[] getColumns() {
        return columns ;
    }
    
    /**
     * 更新時間を取得.
     * @return long 更新時間が返却されます.
     */
    public long getLastUpdateTime() {
        return lastUpdateTime ;
    }
    
    /**
     * 更新時間を更新.
     */
    public void update() {
        lastUpdateTime = System.currentTimeMillis() ;
    }
}

