package org.maachang.proxy.engine.net.http;

import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketTimeoutException;

/**
 * １つのコネクションオブジェクト.
 * 
 * @version 2007/11/17
 * @author  masahito suzuki
 * @since MaachangProxy 1.00
 */
public class ConnectionInfo {
    
    private NetSocketManager manager = null ;
    private KeepAliveTimerManager timerMan = null ;
    private HttpSocket socket = null ;
    private NetOutputStream outputStream = null ;
    private long timeout = -1L ;
    private int count = -1 ;
    
    private ConnectionInfo() {}
    
    protected ConnectionInfo( HttpSocket socket,NetSocketManager manager,KeepAliveTimerManager timerMan ) {
        this.manager = manager ;
        this.timerMan = timerMan ;
        this.socket = socket ;
        this.timeout = timerMan.getTimeout() ;
        this.count = timerMan.getKeepAliveCount() ;
        this.outputStream = null ;
    }
    
    protected void finalize() throws Exception {
        this.destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     * <BR><BR>
     * コネクションオブジェクトを破棄します.
     */
    public synchronized void destroy() {
        this.cancel() ;
        this.manager = null ;
        this.timerMan = null ;
        this.socket = null ;
        this.outputStream = null ;
        this.timeout = -1L ;
        this.count = -1 ;
    }
    
    /**
     * コネクションキャンセル.
     * <BR><BR>
     * コネクション処理をキャンセルします.
     */
    public synchronized void cancel() {
        if( this.outputStream != null ) {
            try {
                this.outputStream.destroy() ;
            } catch( Exception e ) {
            }
            this.outputStream = null ;
        }
    }
    
    /**
     * Httpソケットを取得.
     * <BR>
     * @return HttpSocket HttpSocketが返されます.
     */
    public synchronized HttpSocket getSocket() {
        return this.socket ;
    }
    
    /**
     * KeepAliveタイムアウトを設定.
     * <BR>
     * @param timeout KeepAliveタイムアウト値を設定します.
     */
    public synchronized void setTimeout( long timeout ) {
        this.timeout = timeout ;
    }
    
    /**
     * KeepAliveカウントを設定.
     * <BR>
     * @param count KeepAliveカウント値をミリ秒で設定します.
     */
    public synchronized void setCount( int count ) {
        this.count = count ;
    }
    
    /**
     * KeepAliveタイムアウト値を取得.
     * <BR><BR>
     * @return long KeepAliveタイムアウト値がミリ秒単位で返されます.
     */
    public synchronized long getTimeout() {
        return this.timeout ;
    }
    
    /**
     * KeepAliveカウントを取得.
     * <BR><BR>
     * @return int KeepAliveカウント値が返されます.
     */
    public synchronized int getCount() {
        return this.count ;
    }
    
    /**
     * コネクション更新.
     * <BR>
     * @exception Exception 例外.
     */
    public synchronized void update() throws Exception {
        this.socket.update() ;
        this.cancel() ;
        this.count -- ;
    }
    
    /**
     * コネクション再利用.
     */
    public synchronized boolean recyclingConnection() {
        if( timerMan != null && manager != null ) {
            this.cancel() ;
            timerMan.append( this ) ;
            manager.append( socket ) ;
            return true ;
        }
        return false ;
    }
    
    /**
     * タイマー初期値に設定.
     */
    public synchronized void resetTimer() {
        if( timerMan != null && manager != null ) {
            this.timeout = timerMan.getTimeout() ;
        }
    }
    
    /**
     * 最終利用時間が返されます.
     * <BR>
     * @return long 最終利用時間が返されます.
     */
    public synchronized long getTimer() {
        return this.socket.time() ;
    }
    
    /**
     * 送信用ストリームを取得.
     * <BR>
     * @return OutputStream 送信用ストリームが返されます.
     */
    public synchronized OutputStream getOutputStream()
        throws Exception {
        if( outputStream == null ) {
            outputStream = new NetOutputStream( socket.outputStream() ) ;
        }
        return outputStream ;
    }
    
    /**
     * コネクションクローズを設定.
     * <BR>
     * @param mode [true]の場合、オブジェクト利用後に
     *             コネクションをクローズするか設定します.
     */
    public synchronized void setCloseFlag( boolean mode ) {
        this.socket.setCloseFlag( mode ) ;
    }
    
    /**
     * コネクションクローズを取得.
     * <BR>
     * @return boolean [true]の場合、コネクションクローズを行います.
     */
    public synchronized boolean isCloseFlag() {
        return this.socket.isCloseFlag() ;
    }
    
    /**
     * 送信用ストリームが生成されているかチェック.
     * <BR>
     * @return boolean [true]の場合、送信ストリームが生成されています.
     */
    public synchronized boolean isOutputStream() {
        return ( outputStream == null ) ?
            false : true ;
    }
    
    /**
     * オブジェクトが有効かチェック.
     * <BR>
     * @return boolean [true]の場合、有効です.
     */
    public synchronized boolean isUse() {
        return ( socket == null || socket.isClosed() == true ) ? false : true ;
    }
    
    /**
     * 通信が切断されたかチェック.
     * <BR>
     * @return boolean [true]の場合、切断されています.
     */
    public boolean isCloseSocket() {
        try {
            int n = socket.inputStream().read() ;
            if( n <= -1 ) {
                return true ;
            }
        } catch( SocketTimeoutException se ) {
        } catch( IOException io ) {
            return true ;
        } catch( Exception e ) {
        }
        return false ;
    }
}
