package org.maachang.mimdb.core;

import java.lang.ref.SoftReference;

import org.maachang.mimdb.MimdbException;
import org.maachang.mimdb.core.impl.SqlAnalyzer;
import org.maachang.mimdb.core.util.ObjectKeyValue;
import org.maachang.mimdb.server.ConnectionDefine;
import org.maachang.mimdb.server.MimdbClient;

/**
 * Remote用コネクション.
 * 
 * @version 2014/01/16
 * @author masahito suzuki
 * @since MasterInMemDB 1.02
 */
final class RemoteConnection extends MimdbConnection {
    
    /** デフォルトフェッチサイズ. **/
    protected static final int DEF_FETCH_SIZE = 10 ;
    
    /** クライアントオブジェクト. **/
    protected MimdbClient client = null ;
    
    /** プリコンパイル済みオブジェクト管理. **/
    protected ObjectKeyValue<String,SoftReference<QueryCompileInfo>> preparedList =
        new ObjectKeyValue<String,SoftReference<QueryCompileInfo>>() ;
    
    /** ステートメント. **/
    protected RemoteStatement statement = null ;
    
    /** クローズフラグ. **/
    protected boolean closeFlag = false ;
    
    /** 結果オブジェクト. **/
    protected final RemoteResultImpl result = new RemoteResultImpl() ;
    
    /**
     * コンストラクタ.
     * @param addr 接続先IPアドレスを設定します.
     * @param port 接続先ポート番号を設定します.
     * @param timeout タイムアウト値を設定します.
     * @exception Exception 例外.
     */
    protected RemoteConnection( String addr,int port,int timeout )
        throws Exception {
        client = new MimdbClient( addr,port,timeout ) ;
        statement = new RemoteStatement( this ) ;
    }
    
    /** ファイナライズ. **/
    protected void finalize() throws Exception {
        close() ;
    }
    
    /**
     * オブジェクトクローズ.
     */
    public void close() {
        closeFlag = true ;
        if( client != null ) {
            try {
                client.sendClose( ConnectionDefine.CLOSE_CONNECTION,-1 ) ;
            } catch( Exception e ) {
            }
            client.close() ;
            client = null ;
        }
        if( preparedList != null ) {
            preparedList.clear() ;
            preparedList = null ;
        }
        statement = null ;
    }
    
    /**
     * オブジェクトがクローズしているか取得.
     * @return boolean [true]の場合、クローズしています.
     */
    public boolean isClose() {
        return closeFlag ;
    }
    
    /** チェック処理. **/
    protected void check() {
        if( closeFlag ) {
            throw new MimdbException( "オブジェクトは既にクローズしています" ) ;
        }
    }
    
    /**
     * テーブルオブジェクトを取得
     * @param name 対象のテーブル名を設定します.
     * @return BaseTable テーブルオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public final BaseTable getTable( String name )
        throws Exception {
        check() ;
        try {
            BaseTable ret = client.getTable( name ) ;
            if( ret == null ) {
                throw new MimdbException( "テーブル名[" + name + "]は存在しません" ) ;
            }
            return ret ;
        } catch( RuntimeException r ) {
            throw r ;
        } catch( Exception e ) {
            throw new MimdbException( e ) ;
        }
    }
    
    /**
     * ステートメントオブジェクトを取得.
     * @exception Exception 例外.
     */
    public MimdbStatement getStatement()
        throws Exception {
        check() ;
        statement.clearOffLimit() ;
        return statement ;
    }
    
    /**
     * プリコンパイル済みのステートメントオブジェクトを取得.
     * @param sql 対象のSQL文を設定します.
     * @return MimdbPreparedStatement プリコンパイル済みオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public MimdbPreparedStatement getPreparedStatement( String sql )
        throws Exception {
        check() ;
        return new RemotePreparedStatement( this,sql ) ;
    }
    
    /**
     * タイムアウト値を設定.
     * @param timeout タイムアウト値を設定します.
     */
    public void setTimeout( int timeout ) {
        check() ;
        client.setTimeout( timeout ) ;
    }
    
    /**
     * タイムアウト値を取得.
     * @return int タイムアウト値が返却されます.
     */
    public int getTimeout() {
        check() ;
        return client.getTimeout() ;
    }
    
    /** プリコンパイル済みオブジェクトを作成. **/
    protected static final QueryCompileInfo compile( final RemoteConnection conn,final String sql )
        throws Exception {
        // SQL解析.
        QueryInfo info = new QueryInfo() ;
        SqlAnalyzer.analysis( info,sql ) ;
        if( conn.client.getTable( info.getName() ) == null ) {
            throw new MimdbException( "テーブル名[" + info.getName() + "]は存在しません" ) ;
        }
        // コンパイル処理.
        QueryCompileInfo ret = new QueryCompileInfo() ;
        QueryCompile.compile( ret,info,RemoteTableManager.getInstance() ) ;
        
        return ret ;
    }
    
    /** 指定テーブル名の存在確認. **/
    protected static final void checkTable( final RemoteConnection conn,final String name )
        throws Exception {
        if( conn.client.getTable( name ) == null ) {
            throw new MimdbException( "テーブル名[" + name + "]は存在しません" ) ;
        }
    }
}

