package org.maachang.comet.httpd.engine.comet ;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.httpd.HttpdRequest;

/**
 * コメット管理情報.
 *
 * @version 2007/08/24
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class CometManager {
    
    /**
     * ログ.
     */
    private static final Log LOG = LogFactory.getLog( CometManager.class ) ;
    
    /**
     * コメット管理オブジェクト.
     */
    private Map<String,Comet> manager = null ;
    
    /**
     * プーリング管理.
     */
    private ExecutionPoolComet pool = null ;
    
    /**
     * コメットマネージャ監視スレッド.
     */
    private CometMonitor monitor = null ;
    
    /**
     * コンストラクタ.
     */
    public CometManager() {
        manager = Collections.synchronizedMap( new HashMap<String,Comet>() ) ;
        pool = new ExecutionPoolComet() ;
        monitor = new CometMonitor( manager ) ;
    }
    
    /**
     * コンストラクタ.
     * <BR><BR>
     * 条件を設定してオブジェクトを生成します.
     * <BR>
     * @param length コメット実行用スレッドプーリング数を設定します.
     */
    public CometManager( int length ) {
        manager = Collections.synchronizedMap( new HashMap<String,Comet>() ) ;
        if( length > 0 ) {
            pool = new ExecutionPoolComet( length ) ;
        }
        else {
            pool = new ExecutionPoolComet() ;
        }
        monitor = new CometMonitor( manager ) ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     * <BR><BR>
     * オブジェクトを破棄します.
     */
    public void destroy() {
        if( pool != null ) {
            pool.clear() ;
        }
        if( manager != null && manager.size() > 0 ) {
            Iterator it = manager.keySet().iterator() ;
            while( it.hasNext() ) {
                Comet cmt = manager.get( ( String )it.next() ) ;
                if( cmt != null ) {
                    cmt.clear() ;
                }
            }
            manager.clear() ;
        }
        if( monitor != null ) {
            monitor.clear() ;
        }
        manager = null ;
        pool  = null ;
        monitor = null ;
    }
    
    /**
     * 新しく接続されたコメット情報を設定.
     * <BR><BR>
     * 新しく接続されたコメット情報を設定します.
     * <BR>
     * @param request コネクションリクエストを設定します.
     * @exception Exception 例外.
     */
    public void cometRequest( HttpdRequest request )
        throws Exception {
        if( request == null || request.isUse() == false ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        String groupId = request.getQuery().getParam( "groupId" ) ;
        if( groupId == null ) {
            throw new IOException( "groupIdが設定されていません" ) ;
        }
        Comet comet = null ;
        String path = request.getUrlPath() ;
        comet = manager.get( groupId ) ;
        if( comet == null ) {
            comet = new Comet( groupId,path ) ;
            manager.put( groupId,comet ) ;
        }
        comet.putConnection( request ) ;
    }
    
    /**
     * 対象のコメット情報を実行.
     * <BR><BR>
     * 対象のコメット情報を実行します.
     * <BR>
     * @param args コメット実行処理に渡したい、パラメータを設定します.
     * @param groupId 対象のグループIDを設定します.
     * @exception Exception 例外.
     */
    public void execution( Object args,String groupId )
        throws Exception {
        if( LOG.isDebugEnabled() ) {
            LOG.debug( "executionComet...groupId:" + groupId ) ;
        }
        Comet comet = comet( groupId ) ;
        if( comet != null ) {
            pool.executionComet( comet,args,groupId ) ;
        }
    }
    
    /**
     * コメットオブジェクトを取得.
     * <BR><BR>
     * コメットオブジェクトを取得します.
     * <BR>
     * @param groupId 対象のグループIDを設定します.
     * @return Comet 対象のコメットオブジェクトが返されます.
     */
    public Comet getComet( String groupId ) {
        return comet( groupId ) ;
    }
    
    /**
     * 対象コメットのセッションID群を取得.
     * <BR><BR>
     * 対象コメットのセッションID群を取得します.
     * <BR>
     * @param out 接続中のセッションID群が返されます.
     * @param groupId 対象のグループIDを設定します.
     */
    public void getSessionIds( ArrayList<String> out,String groupId ) {
    	if( out == null ) {
    		return ;
    	}
        Comet comet = comet( groupId ) ;
        if( comet != null ) {
            comet.getConnectSessionIds( out ) ;
        }
        return ;
    }
    
    /**
     * 対象コメットの接続数を取得.
     * <BR><BR>
     * 対象コメットの接続数を取得します.
     * <BR>
     * @param groupId 対象のグループIDを設定します.
     * @return int 接続数が返されます.
     */
    public int getConnectSize( String groupId ) {
        Comet comet = comet( groupId ) ;
        if( comet != null ) {
            return comet.getConnectSize() ;
        }
        return 0 ;
    }
    
    /**
     * 全コネクション数を取得.
     * <BR><BR>
     * 全体のコネクション数を取得します.
     * <BR>
     * @return int 全体のコネクション数が返されます.
     */
    public int getConnectCount() {
        int ret = 0 ;
        if( manager == null && manager.size() <= 0 ) {
            return 0 ;
        }
        Iterator it = manager.keySet().iterator() ;
        while( it.hasNext() ) {
            Comet cmt = manager.get( ( String )it.next() ) ;
            if( cmt != null ) {
                ret += cmt.getConnectSize() ;
            }
        }
        return ret ;
    }
    
    /**
     * コメット管理グループID群を取得.
     * <BR><BR>
     * コメット管理グループID群を取得します.
     * <BR>
     * @return Iterator 管理されているIteratorが返されます.
     */
    public Iterator getGroupIterator() {
        Iterator ret = null ;
        if( manager != null ) {
            ret = manager.keySet().iterator() ;
        }
        return ret ;
    }
    
    /**
     * コメット管理数を取得.
     * <BR><BR>
     * コメット管理数を取得します.
     * <BR>
     * @return int コメット管理数が返されます.
     */
    public int size() {
        int ret = 0 ;
        if( manager != null ) {
            ret = manager.size() ;
        }
        return ret ;
    }
    
    /**
     * コメット実行用プーリング数を取得.
     * <BR><BR>
     * コメット実行用プーリング数を取得します.
     * <BR>
     * @return int コメット実行用プーリング数を取得します.
     */
    public int getPoolSize() {
        return pool.size() ;
    }
    
    /**
     * 指定グループIDが存在するかチェック.
     * <BR><BR>
     * 指定グループIDが存在するかチェックします.
     * <BR>
     * @param groupId 対象のグループIDを設定します.
     * @return boolean [true]の場合存在します.
     */
    public boolean isComet( String groupId ) {
        return ( comet( groupId ) != null ) ? true : false ;
    }
    
    /**
     * オブジェクトが有効であるかチェック.
     * <BR><BR>
     * オブジェクトが有効であるかチェックします.
     * <BR>
     * @return boolean [true]の場合有効です.
     */
    public boolean isUse() {
        if( manager != null && pool != null && pool.isUse() == true ) {
            return true ;
        }
        return false ;
    }
    
    /**
     * コメット情報を取得.
     */
    private synchronized Comet comet( String groupId ) {
        Comet ret = null ;
        if( manager != null ) {
            ret = manager.get( groupId ) ;
        }
        return ret ;
    }
}

