package org.maachang.mimdb.server ;

import java.lang.ref.SoftReference;
import java.nio.channels.SocketChannel;

import org.maachang.mimdb.MimdbException;
import org.maachang.mimdb.core.MimdbResult;
import org.maachang.mimdb.core.QueryCompileInfo;
import org.maachang.mimdb.core.util.ByteArrayIO;
import org.maachang.mimdb.core.util.NumberKeyValue;

/**
 * Mimdb通信要素.
 * 
 * @version 2014/01/16
 * @author  masahito suzuki
 * @since MasterInMemDB 1.02
 */
public final class MimdbConnectElement {
    
    /** SocketChannel. **/
    protected SocketChannel channel = null ;
    
    /** 最終アクセス時間. **/
    protected long lastAccess = System.currentTimeMillis() ;
    
    /** 受信バッファ. **/
    protected ByteArrayIO recvBuffer = new ByteArrayIO( MimdbServer.RECV_BYTE_ARRAY_LENGTH ) ;
    protected int recvType = 0 ;
    protected int nowRecvLength = 0 ;
    
    /** 送信バッファ. **/
    protected byte[] sendHeader = null ;
    protected int nowSendHeaderOffset = 0 ;
    protected byte[] sendBuffer = null ;
    protected int nowSendLength = 0 ;
    protected int nowSendOffset = 0 ;
    
    /** コンパイル済みIDシーケンス管理. **/
    protected int preparedSeqId = 0 ;
    
    /** プリコンパイル済みオブジェクト管理. **/
    protected NumberKeyValue<SoftReference<QueryCompileInfo>> preparedList =
        new NumberKeyValue<SoftReference<QueryCompileInfo>>() ;
    
    /** 結果情報IDシーケンス管理. **/
    protected int resultSeqId = 0 ;
    
    /** 結果情報管理. **/
    protected NumberKeyValue<MimdbResult> resultList = new NumberKeyValue<MimdbResult>() ;
    
    /**
     * コンストラクタ.
     */
    public MimdbConnectElement() {
        
    }
    
    /**
     * デストラクタ.
     */
    protected final void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     */
    public final void destroy() {
        if( channel != null ) {
            try {
                channel.socket().close() ;
            } catch( Throwable e ) {
            }
            channel = null ;
        }
        
        if( recvBuffer != null ) {
            recvBuffer.clear() ;
            recvBuffer = null ;
        }
        
        sendBuffer = null ;
        sendHeader = null ;
        
        if( preparedList != null ) {
            preparedList.clear() ;
            preparedList = null ;
        }
        
        if( resultList != null ) {
            if( resultList.size() > 0 ) {
                NumberKeyValue<MimdbResult> it = resultList.reset() ;
                while( it.hasNext() ) {
                    resultList.get( it.next() ).clear() ;
                }
                resultList.clear() ;
            }
            resultList = null ;
        }
        
    }
    
    /**
     * 全要求をクリア.
     */
    public final void clear() {
        if( preparedList != null ) {
            preparedList.clear() ;
        }
        if( resultList != null ) {
            if( resultList.size() > 0 ) {
                NumberKeyValue<MimdbResult> it = resultList.reset() ;
                while( it.hasNext() ) {
                    resultList.get( it.next() ).clear() ;
                }
                resultList.clear() ;
            }
        }
        preparedSeqId = 0 ;
        resultSeqId = 0 ;
    }
    
    /**
     * コンパイル済みオブジェクトのシーケンスIDを取得.
     * @return int シーケンスIDが返却されます.
     */
    public final int getPreparedSequenceId() {
        if( preparedList.size() > ConnectionDefine.MAX_SEQUENCE_ID ) {
            throw new MimdbException( "管理可能なコンパイル済みオブジェクト数を越えています" ) ;
        }
        while( true ) {
            preparedSeqId ++ ;
            if( preparedSeqId > ConnectionDefine.MAX_SEQUENCE_ID ) {
                preparedSeqId = 0 ;
            }
            if( !preparedList.containsKey( preparedSeqId ) ) {
                return preparedSeqId ;
            }
        }
    }
    
    /**
     * 結果オブジェクトのシーケンスIDを取得.
     * @return int シーケンスIDが返却されます.
     */
    public final int getResultSetSequenceId() {
        if( resultList.size() > ConnectionDefine.MAX_SEQUENCE_ID ) {
            throw new MimdbException( "管理可能な結果オブジェクト数を越えています" ) ;
        }
        while( true ) {
            resultSeqId ++ ;
            if( resultSeqId > ConnectionDefine.MAX_SEQUENCE_ID ) {
                resultSeqId = 0 ;
            }
            if( !resultList.containsKey( resultSeqId ) ) {
                return resultSeqId ;
            }
        }
    }
}
