package org.maachang.comet.proxy ;

import java.net.InetAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.net.HttpAcceptThread;
import org.maachang.comet.net.HttpCallbackReceive;
import org.maachang.comet.net.HttpSocketManager;
import org.maachang.util.SequenceSync;

/**
 * Proxyサービス.
 * 
 * @version 2007/11/17
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class ProxyService {
    
    private static final Log LOG = LogFactory.getLog( ProxyService.class ) ;
    private static final int MIN_POOL = 5 ;
    private static final int MAX_POOL = 150 ;
    
    private HttpAcceptThread accept = null ;
    private ProxyReceiveThread server = null ;
    private ProxyPoolThread[] pool = null ;
    private SequenceSync sequence = null ;
    
    /**
     * コンストラクタ.
     */
    public ProxyService() {
        
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.close() ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * ProxyServiceをオープンします.
     * <BR>
     * @param executionObject 受信コールバックオブジェクトを設定します.
     * @param maxConnect 最大コネクション数を設定します.
     * @param length Threadプーリング数を設定します.
     * @param port サーバポート番号を設定します.
     * @exception Exception 例外.
     */
    public void open( HttpCallbackReceive executionObject,int maxConnect,int length,int port )
        throws Exception {
        this.open( executionObject,maxConnect,length,null,port ) ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * ProxyServiceをオープンします.
     * <BR>
     * @param executionObject 受信コールバックオブジェクトを設定します.
     * @param opt SSLオプションを設定します.
     * @param maxConnect 最大コネクション数を設定します.
     * @param length Threadプーリング数を設定します.
     * @param addr サーバアドレスを設定します.
     * @param port サーバポート番号を設定します.
     * @exception Exception 例外.
     */
    public void open( HttpCallbackReceive executionObject,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 {
        	ProxyServerImpl server = new ProxyServerImpl( addr,port,maxConnect ) ;
            HttpSocketManager manager = new HttpSocketManager() ;
            
            this.accept = new HttpAcceptThread( server,manager ) ;
            this.sequence = new SequenceSync() ;
            this.server = new ProxyReceiveThread( manager ) ;
            this.pool = new ProxyPoolThread[ length ] ;
            for( int i = 0 ; i < length ; i ++ ) {
                this.pool[ i ] = new ProxyPoolThread( this.server.getUseQueue(),manager,executionObject,this.sequence ) ;
            }
        } catch( Exception e ) {
            LOG.error( "## error",e ) ;
            this.close() ;
            throw e ;
        }
    }
    
    /**
     * クローズ処理.
     * <BR><BR>
     * ProxyServiceをクローズします.
     */
    public void close() {
        if( this.accept != null ) {
            this.accept.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 ;
    }
}
