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

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * １つのコメット実行用スレッド.
 *
 * @version 2007/08/24
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
class ExecutionOnePoolComet extends Thread {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( ExecutionPoolComet.class ) ;
    
    /**
     * アイドルタイム.
     */
    private static final long IDLE_TIME = 30L ;
    
    /**
     * コメット実行待ちキュー.
     */
    private ArrayList<CometParamPlus> queue = null ;
    
    /**
     * 停止フラグ.
     */
    private volatile boolean stopFlag = false ;
    
    /**
     * コメット実行フラグ.
     */
    private volatile boolean executionComet = false ;
    
    /**
     * 停止フラグ用同期.
     */
    private Object sync = new Object() ;
    
    /**
     * コンストラクタ.
     */
    public ExecutionOnePoolComet() {
        queue = new ArrayList<CometParamPlus>() ;
        this.setDaemon( true ) ;
        this.start() ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.clear() ;
    }
    
    /**
     * クリア.
     */
    public void clear() {
        stopThread() ;
        clearQueue() ;
    }
    
    /**
     * 処理対象のコメットオブジェクトを追加.
     * <BR><BR>
     * @param comet 対象のコメット情報を設定します.
     * @param args コメット実行処理に渡したい、パラメータを設定します.
     * @param groupId 対象のグループIDを設定します.
     * @return boolean [false]の場合、このプーリングスレッドは実行中です.
     */
    public synchronized boolean executionComet( Comet comet,Object args,String groupId ) {
        if( isExecutionMode() == true ) {
            return false ;
        }
        CometParamPlus cometParam = new CometParamPlus() ;
        cometParam.comet = comet ;
        cometParam.args = args ;
        cometParam.groupId = groupId ;
        queue.add( cometParam ) ;
        executionMode() ;
        return true ;
    }
    
    /**
     * 実行状態を取得.
     * <BR><BR>
     * @return boolean 実行状態が返されます.
     */
    public boolean isStopThread() {
        boolean ret = false ;
        synchronized( sync ) {
            ret = stopFlag ;
        }
        return ret ;
    }
    
    /**
     * コメット実行処理中か取得.
     * <BR><BR>
     * @return boolean [true]の場合、実行中です.
     */
    public boolean isExecution() {
        return isExecutionMode() ;
    }
    
    
    
    /**
     * スレッド処理.
     */
    public void run() {
        try {
            for( ;; ) {
                if( isStopThread() == true ) {
                    break ;
                }
                try { Thread.sleep( IDLE_TIME ) ; } catch( Exception e ) {}
                try {
                    CometParamPlus cometParam = get() ;
                    if( cometParam != null ) {
                        Comet comet = cometParam.comet ;
                        String groupId = cometParam.groupId ;
                        Object args = cometParam.args ;
                        if( comet != null && comet.getConnectSize() > 0 ) {
                            comet.send( args,groupId ) ;
                        }
                        endExecutionMode() ;
                    }
                } catch( OutOfMemoryError mm ) {
                    LOG.error( "OutOfMemoryError",mm ) ;
                } catch( Exception e ) {
                    LOG.error( "error",e ) ;
                } finally {
                }
            }
        } finally {
            LOG.warn( "## stopThread:" + this.getClass().getName() ) ;
        }
    }
    
    
    private synchronized  CometParamPlus get() {
        if( queue != null && queue.size() > 0 ) {
            return queue.remove( 0 ) ;
        }
        return null ;
    }
    
    private void stopThread() {
        synchronized( sync ) {
            stopFlag = true ;
        }
    }
    
    private synchronized void clearQueue() {
        queue.clear() ;
    }
    
    private synchronized void executionMode() {
        executionComet = true ;
    }
    
    private synchronized void endExecutionMode() {
        executionComet = false ;
    }
    
    private synchronized boolean isExecutionMode() {
        return executionComet ;
    }
}

/**
 * 実行パラメータ付きコメット.
 */
class CometParamPlus {
    public String groupId = null ;
    public Object args = null ;
    public Comet comet = null ;
}
