package org.maachang.comet.net.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedList;

/**
 * 受信用バッファ.
 * 
 * @version 2008/07/08
 * @author masahito suzuki
 * @since MaachangComet 1.1F
 */
public class ReceiveBuffer {
    
    /**
     * バッファ情報管理キュー.
     */
    private final LinkedList<byte[]> queue = new LinkedList<byte[]>() ;
    
    /**
     * 総データサイズ.
     */
    private int length = 0 ;
    
    /**
     * NioElement停止フラグ.
     */
    private boolean useConnectFlag = true ;
    
    /**
     * 同期オブジェクト.
     */
    private final Object sync = new Object() ;
    
    /**
     * コンストラクタ.
     */
    protected ReceiveBuffer() {
    }
    
    protected void finalize() throws Exception {
        this.destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     */
    public void destroy() {
        synchronized( sync ) {
            queue.clear() ;
            length = 0 ;
            useConnectFlag = false ;
        }
    }
    
    /**
     * データリセット.
     */
    public void reset() {
        synchronized( sync ) {
            queue.clear() ;
            length = 0 ;
        }
    }
    
    /**
     * 受信されたデータをセット.
     * @param buffer 対象のByteBufferを設定します.
     * @exception Exception 例外.
     */
    public void put( ByteBuffer buffer )
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは既に破棄されています" ) ;
        }
        if( buffer == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        int len = buffer.limit() ;
        if( len <= 0 ) {
            return ;
        }
        byte[] bin = new byte[ len ] ;
        buffer.get( bin,0,len ) ;
        synchronized( sync ) {
            queue.add( bin ) ;
            length += len ;
        }
    }
    
    /**
     * １つのバッファ内容を取得.
     * @return byte[] １つのバッファ内容が返されます.
     */
    public byte[] get() {
        byte[] ret = null ;
        synchronized( sync ) {
            if( queue.size() > 0 ) {
                if( ( ret = queue.removeFirst() ) != null ) {
                    length -= ret.length ;
                }
            }
        }
        return ret ;
    }
    
    /**
     * 現在の受信バッファ長を取得.
     * @return int 現在の受信バッファ長が返されます.
     */
    public int length() {
        int ret ;
        synchronized( sync ) {
            ret = length ;
        }
        return ret ;
    }
    
    /**
     * コネクション有効チェック.
     * @return boolean [true]の場合、動作しています.
     */
    public boolean isUse() {
        boolean ret ;
        synchronized( sync ) {
            ret = useConnectFlag ;
        }
        return ret ;
    }
}
