package org.maachang.comet.net.nio ;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;

/**
 * １つのコネクションオブジェクト.
 * 
 * @version 2008/05/28
 * @author  masahito suzuki
 * @since   MaachangComet 1.1B
 */
class ConnectionInfoImpl implements ConnectionInfo {
    
    private KeepAliveBean keepAlive = null ;
    private NioElement element = null ;
    private InetAddress address = null ;
    private int port = -1 ;
    private boolean cloesFlag = false ;
    private boolean cometFlag = false ;
    private final NioInputStream inputStream = new NioInputStream() ;
    private final NioOutputStream outputStream = new NioOutputStream() ;
    
    /**
     * コンストラクタ.
     */
    public ConnectionInfoImpl() {
        
    }
    
    protected void finalize() throws Exception {
        this.destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     */
    public void destroy() {
        if( element != null ) {
            element.destroy() ;
        }
        inputStream.resetObject() ;
        outputStream.resetObject() ;
        keepAlive = null ;
        element = null ;
        address = null ;
        port = -1 ;
        cloesFlag = false ;
        cometFlag = false ;
    }
    
    /**
     * 生成処理.
     * @param element 対象のNIO要素を設定します.
     * @return ConnectionInfo このオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public ConnectionInfo create( NioElement element )
        throws Exception {
        this.clear() ;
        if( element == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        else if( element.isUse() == false ) {
            throw new IOException( "コネクションは切断されています" ) ;
        }
        KeepAliveBean keepAlive = ( KeepAliveBean )element.getObject() ;
        if( keepAlive == null ) {
            keepAlive = KeepAliveFactory.getInstance().getBean() ;
            element.setObject( keepAlive ) ;
        }
        this.element = element ;
        this.keepAlive = keepAlive ;
        this.address = element.getChannel().socket().getInetAddress() ;
        this.port = element.getChannel().socket().getPort() ;
        return this ;
    }
    
    /**
     * オブジェクトクリア.
     */
    public void clear() {
        inputStream.resetObject() ;
        outputStream.resetObject() ;
        keepAlive = null ;
        element = null ;
        address = null ;
        port = -1 ;
        cloesFlag = false ;
    }
    
    /**
     * オブジェクト複製.
     * @return ConnectionInfo 複製されたオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public ConnectionInfo copy() throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは破棄されています" ) ;
        }
        ConnectionInfoImpl ret = new ConnectionInfoImpl() ;
        // comet用として、InputStreamを停止.
        inputStream.resetObject() ;
        ret.keepAlive = keepAlive ;
        ret.element = element ;
        ret.address = address ;
        ret.port = port ;
        ret.cloesFlag = cloesFlag ;
        return ret ;
    }
    
    /**
     * Nio要素を取得.
     * @return NioElement Nio要素が返されます.
     */
    public NioElement getElement() {
        if( isUse() == false ) {
            return null ;
        }
        return element ;
    }
    
    /**
     * KeepAliveタイムアウト値を設定.
     * @param time KeepAliveタイムアウト値を設定します.
     */
    public void setTimeout( int time ) {
        keepAlive.setTime( time ) ;
    }
    
    /**
     * KeepAliveタイムアウト値を取得.
     * @return long KeepAliveタイムアウト値が返されます.
     */
    public long getTimeout() {
        return keepAlive.getTime() ;
    }
    
    /**
     * KeepAliveカウント値を取得.
     * @return int KeepAliveカウント値が返されます.
     */
    public int getCount() {
        return keepAlive.getCount() ;
    }
    
    /**
     * OutputStreamを取得.
     * @return OutputStream OutputStreamが返されます.
     */
    public OutputStream getOutputStream()
        throws Exception {
        if( isUse() == false ) {
            return null ;
        }
        return outputStream.create( element ) ;
    }
    
    /**
     * InputStreamを取得.
     * @return InputStreamが返されます.
     */
    public InputStream getInputStream()
        throws Exception {
        if( isUse() == false ) {
            return null ;
        }
        return inputStream.create( element ) ;
    }
    
    /**
     * InputStreamを取得.
     * @param timeout タイムアウト値を設定します.
     * @return InputStreamが返されます.
     */
    public InputStream getInputStream( long timeout )
        throws Exception {
        if( isUse() == false ) {
            return null ;
        }
        return inputStream.create( element,timeout ) ;
    }
    
    /**
     * 接続先アドレスを取得.
     * @return InetAddress 接続先アドレスが返されます.
     */
    public InetAddress getInetAddress() {
        return address ;
    }
    
    /**
     * 接続先ポートを取得.
     * @return int 接続先ポート番号が返されます.
     */
    public int getPort() {
        return port ;
    }
    
    /**
     * コネクションクローズフラグを設定.
     * @param mode [true]の場合、コネクションクローズを行います.
     */
    public void setCloseFlag( boolean mode ) {
        cloesFlag = mode ;
    }
    
    /**
     * KeepAliveが有効な場合のコネクション再利用チェック.
     * @return boolean [true]の場合、再利用可能です.
     */
    public boolean recyclingConnection() {
        if( isUse() == false ) {
            return false ;
        }
        int cnt = keepAlive.getCount() - 1 ;
        keepAlive.setCount( cnt ) ;
        if( cnt <= 0 ) {
            return false ;
        }
        element.setExecutionFlag( false ) ;
        return true ;
    }
    
    /**
     * コネクションクローズフラグを取得.
     * @return boolean [true]の場合、コネクションはクローズします.
     */
    public boolean isCloseFlag() {
        return cloesFlag ;
    }
    
    /**
     * オブジェクト有効チェック.
     * @return boolean [true]の場合、有効です.
     */
    public boolean isUse() {
//        boolean ret = ( element == null || element.getChannel() == null ||
//            element.getChannel().isConnected() == false ) ? false : true ;
        boolean ret = ( element == null || element.getChannel() == null ) ? false : true ;
        if( ret == false ) {
            if( element != null ) {
                element.destroy() ;
            }
        }
        return ret ;
    }
    
    /**
     * コメット実行設定.
     */
    public void cometOn() {
        cometFlag = true ;
    }
    
    /**
     * コメット実行フラグ.
     */
    public boolean isComet() {
        boolean ret = cometFlag ;
        cometFlag = false ;
        return ret ;
    }
}
