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

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

/**
 * １つのコメット実行用スレッド.
 *
 * @version 2007/08/24
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
class ExecutionOnePoolComet extends Thread {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( ExecutionOnePoolComet.class ) ;
    
    /**
     * コメット実行待ちキュー.
     */
    private final SimpleQueue<CometParamPlus> queue = new SimpleQueue<CometParamPlus>() ;
    
    /**
     * 停止フラグ.
     */
    private volatile boolean stopFlag = false ;
    
    /**
     * コメット実行フラグ.
     */
    private volatile boolean executionComet = false ;
    
    /**
     * 停止フラグ用同期.
     */
    private Object sync = new Object() ;
    
    /**
     * コンストラクタ.
     */
    public ExecutionOnePoolComet() {
        this.setDaemon( true ) ;
        this.start() ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.destroy() ;
    }
    
    /**
     * クリア.
     */
    public void destroy() {
        stopThread() ;
        queue.destroy() ;
    }
    
    /**
     * 処理対象のコメットオブジェクトを追加.
     * <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( ;; ) {
                boolean exec = false ;
                if( isStopThread() == true ) {
                    break ;
                }
                try {
                    Thread.sleep( 5L ) ;
                    CometParamPlus cometParam = queue.get() ;
                    if( cometParam != null && cometParam.comet != null &&
                        cometParam.comet.getConnectSize() > 0 ) {
                        cometParam.comet.send( cometParam.args,cometParam.groupId ) ;
                        exec = true ;
                    }
                } catch( InterruptedException ie ) {
                    break ;
                } catch( OutOfMemoryError mm ) {
                    LOG.error( "OutOfMemoryError",mm ) ;
                } catch( Exception e ) {
                    LOG.error( "error",e ) ;
                } finally {
                    if( exec ) {
                        endExecutionMode() ;
                    }
                }
            }
        } finally {
            LOG.warn( "## stopThread:" + this.getClass().getName() ) ;
        }
    }
    
    
    private void stopThread() {
        synchronized( sync ) {
            stopFlag = true ;
        }
    }
    
    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 ;
}
