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.Map;

import org.maachang.comet.httpd.HttpdRequest;

/**
 * コメット管理情報.
 *
 * @version 2007/08/24
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class CometManager {
    
    /**
     * コメット管理オブジェクト.
     */
    private Map<String,Comet> manager = null ;
    
    /**
     * プーリング管理.
     */
    private ExecutionPoolComet pool = null ;
    
    /**
     * コメットタイムアウト管理.
     */
    private TimeoutCometMonitor monitor = null ;
    
    /**
     * コンストラクタ.
     */
    public CometManager() {
        manager = Collections.synchronizedMap( new HashMap<String,Comet>() ) ;
        pool = new ExecutionPoolComet() ;
        monitor = new TimeoutCometMonitor( 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 TimeoutCometMonitor( manager ) ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     * <BR><BR>
     * オブジェクトを破棄します.
     */
    public void destroy() {
        if( pool != null ) {
            pool.clear() ;
        }
        if( manager != null && manager.size() > 0 ) {
            Object[] gps = manager.keySet().toArray() ;
            int len = gps.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                Comet cmt = manager.get( ( String )gps[ i ] ) ;
                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を設定します.
     */
    public void execution( Object args,String 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 groupId 対象のグループIDを設定します.
     * @return ArrayList<String> 接続中のセッションID群が返されます.
     */
    public ArrayList<String> getSessionIds( String groupId ) {
        Comet comet = comet( groupId ) ;
        if( comet != null ) {
            return comet.getConnectSessionIds() ;
        }
        return null ;
    }
    
    /**
     * 対象コメットの接続数を取得.
     * <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 ;
        }
        Object[] gps = manager.keySet().toArray() ;
        int len = gps.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            Comet cmt = manager.get( ( String )gps[ i ] ) ;
            if( cmt != null ) {
                ret += cmt.getConnectSize() ;
            }
        }
        return ret ;
    }
    
    /**
     * コメット管理グループID群を取得.
     * <BR><BR>
     * コメット管理グループID群を取得します.
     * <BR>
     * @return Object[] 管理されているグループID群が返されます.
     */
    public Object[] getGroupIds() {
        Object[] ret = null ;
        if( manager != null ) {
            ret = manager.keySet().toArray() ;
        }
        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 ;
    }
}

