package org.maachang.comet.net.nio ;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.net.HttpServer;
import org.maachang.comet.net.ssl.SslOption;
import org.maachang.util.SequenceSync;

/**
 * ネットワークサービス.
 * 
 * @version 2008/05/28
 * @author  masahito suzuki
 * @since   MaachangComet 1.1B
 */
public class NioService {
    
    private static final Log LOG = LogFactory.getLog( NioService.class ) ;
    private static final int MIN_POOL = 5 ;
    private static final int MAX_POOL = 500 ;
    private static final double TO_SSL_LENGTH = 0.75f ;
    private static final int RECV_THEAD_CODE = 4 ;
    
    private NioTcpServer httpBase = null ;
    private NioSslServer sslBase = null ;
    private NioPoolThread[] pool = null ;
    
    /**
     * コンストラクタ.
     */
    public NioService() {
        
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.close() ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * NetServiceをオープンします.
     * <BR>
     * @param call 受信コールバックオブジェクトを設定します.
     * @param http HTTPサーバオブジェクトを設定します.
     * @param ssl SSLサーバオブジェクトを設定します.
     * @param pool プーリング数を設定します.
     * @exception Exception 例外.
     */
    public void open( HttpReceiveCallback call,HttpServer http,HttpServer ssl,int pool )
        throws Exception {
        if( call == null || http == null || http.isClosed() == true ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( pool <= MIN_POOL ) {
            pool = MIN_POOL ;
        }
        else if( pool >= MAX_POOL ) {
            pool = MAX_POOL ;
        }
        this.close() ;
        int all = pool / RECV_THEAD_CODE ;
        int tcpRecvLen = ( int )( all * TO_SSL_LENGTH ) ;
        int sslRecvLen = all - tcpRecvLen ;
        if( ssl == null ) {
            tcpRecvLen = all ;
            sslRecvLen = 0 ;
        }
        if( LOG.isDebugEnabled() ) {
            LOG.debug( "## tcpRecvLen:" + tcpRecvLen + " sslRecvLen:" + sslRecvLen ) ;
        }
        try {
            ReceiveLinkQueue queue = new ReceiveLinkQueue() ;
            this.httpBase = new NioTcpServer( tcpRecvLen,http.channel(),queue ) ;
            if( ssl != null ) {
                this.sslBase = new NioSslServer( sslRecvLen,ssl.channel(),( SslOption )ssl.option(),queue ) ;
            }
            SequenceSync seq = new SequenceSync() ;
            this.pool = new NioPoolThread[ pool ] ;
            for( int i = 0 ; i < pool ; i ++ ) {
                this.pool[ i ] = new NioPoolThread( call,queue,seq ) ;
            }
        } catch( Exception e ) {
            LOG.error( "## error",e ) ;
            this.close() ;
            throw e ;
        }
    }
    
    /**
     * クローズ処理.
     * <BR><BR>
     * NetServiceをクローズします.
     */
    public void close() {
        if( pool != null ) {
            int len = pool.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                if( pool[ i ] != null ) {
                    pool[ i ].destroy() ;
                }
                pool[ i ] = null ;
            }
        }
        if( httpBase != null ) {
            httpBase.destroy() ;
        }
        if( sslBase != null ) {
            sslBase.destroy() ;
        }
        pool = null ;
        httpBase = null ;
        sslBase = null ;
    }
}
