package org.maachang.comet.net ;

import java.net.InetAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.util.SequenceSync;

/**
 * ネットワークサービス.
 * 
 * @version 2007/11/17
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class NetService {
    
    private static final Log LOG = LogFactory.getLog( NetService.class ) ;
    private static final int MIN_POOL = 5 ;
    private static final int MAX_POOL = 500 ;
    
    private SslServerFactory sslFactory = null ;
    private HttpAcceptThread accept = null ;
    private HttpAcceptThread sslAccept = null ;
    private NetReceiveThread server = null ;
    private NetPoolThread[] pool = null ;
    private SequenceSync sequence = null ;
    
    /**
     * コンストラクタ.
     */
    public NetService() {
        
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.close() ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * NetServiceをオープンします.
     * <BR>
     * @param executionObject 受信コールバックオブジェクトを設定します.
     * @param opt SSLオプションを設定します.
     * @param maxConnect 最大コネクション数を設定します.
     * @param length Threadプーリング数を設定します.
     * @param port サーバポート番号を設定します.
     * @exception Exception 例外.
     */
    public void open( HttpCallbackReceive executionObject,SslOption opt,int maxConnect,int length,int port )
        throws Exception {
        this.open( executionObject,opt,maxConnect,length,null,port ) ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * NetServiceをオープンします.
     * <BR>
     * @param executionObject 受信コールバックオブジェクトを設定します.
     * @param opt SSLオプションを設定します.
     * @param maxConnect 最大コネクション数を設定します.
     * @param length Threadプーリング数を設定します.
     * @param addr サーバアドレスを設定します.
     * @param port サーバポート番号を設定します.
     * @exception Exception 例外.
     */
    public void open( HttpCallbackReceive executionObject,SslOption opt,int maxConnect,int length,InetAddress addr,int port )
        throws Exception {
        if( executionObject == null ) {
            throw new IllegalArgumentException( "対象条件は不正です" ) ;
        }
        if( length <= MIN_POOL ) {
            length = MIN_POOL ;
        }
        else if( length >= MAX_POOL ) {
            length = MAX_POOL ;
        }
        this.close() ;
        try {
            int sslCon = -1 ;
            if( opt != null ) {
                sslCon = maxConnect / 4 ;
                if( sslCon <= 0 ) {
                    sslCon = 1 ;
                }
                maxConnect -= sslCon ;
            }
            HttpServer server = new NetServerImpl( addr,port,maxConnect ) ;
            HttpSocketManager manager = new HttpSocketManager() ;
            
            this.accept = new HttpAcceptThread( server,manager ) ;
            if( sslCon > 0 ) {
                this.sslFactory = new SslServerFactory( opt ) ;
                HttpServer sslServer = new NetSslServerImpl( this.sslFactory,
                    opt.getSslAddress(),opt.getSslPort(),sslCon ) ;
                this.sslAccept = new HttpAcceptThread( sslServer,manager ) ;
            }
            else {
                this.sslFactory = null ;
                this.sslAccept = null ;
            }
            
            this.sequence = new SequenceSync() ;
            KeepAliveTimerManager timerMan = new KeepAliveTimerManager() ;
            this.server = new NetReceiveThread( timerMan,manager ) ;
            this.pool = new NetPoolThread[ length ] ;
            for( int i = 0 ; i < length ; i ++ ) {
                this.pool[ i ] = new NetPoolThread( this.server.getUseQueue(),executionObject,this.sequence ) ;
            }
        } catch( Exception e ) {
            LOG.error( "## error",e ) ;
            this.close() ;
            throw e ;
        }
    }
    
    /**
     * クローズ処理.
     * <BR><BR>
     * NetServiceをクローズします.
     */
    public void close() {
        if( this.accept != null ) {
            this.accept.destroy() ;
        }
        if( this.sslAccept != null ) {
            this.sslAccept.destroy() ;
        }
        if( this.server != null ) {
            this.server.destroy() ;
        }
        if( this.pool != null ) {
            int len = pool.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                if( pool[ i ] != null ) {
                    pool[ i ].destroy() ;
                }
                pool[ i ] = null ;
            }
        }
        this.accept = null ;
        this.server = null ;
        this.pool = null ;
        this.sslFactory = null ;
    }
    
    /**
     * SSLサーバファクトリを取得.
     * <BR><BR>
     * SSLサーバファクトリを取得します.
     * <BR>
     * @return SslServerFactory SSLサーバファクトリが返されます.
     */
    public SslServerFactory getSslServerFactory() {
        return this.sslFactory ;
    }
}
