/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2000-2002, Eric Crahen, See LGPL.TXT for details
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#ifndef __ZTSYNCEXECUTOR_H__
#define __ZTSYNCEXECUTOR_H__

#include "zthread/ZThread.h"
#include "zthread/Executor.h"
#include "zthread/Mutex.h"

namespace ZThread {


/**
 * @class SyncExecutor
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-04T20:25:02-0500>
 * @version 2.0.2
 *
 * This Executor runs a task in the thread that enqueued that task. It
 * ensures that only 1 task is executed at any given time by any thread
 * using this Executor. 
 */
template <class L=Mutex, bool CONSUMING=true>
class ZTHREAD_API SyncExecutor : public Executor {
  private:

  SyncExecutor(SyncExecutor*);
  SyncExecutor(const SyncExecutor&);
  SyncExecutor& operator=(const SyncExecutor&);
  
  protected:
  
  //! Typedef
  typedef L LOCK;

  //! Serialize access
  LOCK _lock;
  //! Cancellation flag
  bool _canceled;

  public:

  /**
   * Create a new SyncExecutor
   */
  SyncExecutor() : _canceled(false) {}


  /**
   * Destroy this Executor
   */
  virtual ~SyncExecutor() throw() {}

  /**
   * Enqueue another task for execution, blocking the thread until the
   * task is executed.
   *
   * @param Runnable task - task to execute
   * @exception InterruptedException 
   *
   * @pre The executor must not be canceled. A canceled
   * executor will ignore execute() requests.
   *
   * @post The given task will be executed as soon as 
   * possible by the executor
   */
  virtual void execute(Runnable* task)
    throw(Synchronization_Exception) {
    
    if(_canceled) // Avoid excess locking in the canceled state
      throw Cancelation_Exception();
    
    Guard<LOCK> g(_lock);
    
    if(_canceled)
      throw Cancelation_Exception();
    
    if(task)
      task->run();

    if(CONSUMING)
      delete task;

  }
  
  /**
   * Stop the execution of additional tasks by this executor.
   * After this method has be invoked then the Executor will
   * completed when the last task it was previously assigned is 
   * completed. 
   *
   * @exception InterruptedException 
   * 
   * @post the executor no longer accepts new tasks. At this point
   * the executor has a limited lifetime and is safe to join
   */
  virtual void cancel() 
    throw(Synchronization_Exception) {
      
    Guard<LOCK> g(_lock);
    _canceled = true;
    
  }
  
  /**
   * Check the cancelation status of this Executor
   * 
   * @return bool - Executor canceled
   * @see Cancelable::isCanceled()
   */
  inline virtual bool isCanceled()
    throw(Synchronization_Exception) {
    
    Guard<LOCK> g(_lock);
    return _canceled;

  }

  /**
   * Wait for this Executor to complete. The calling thread is
   * blocked until the last task has been completed by this executor
   * or until the calling thread has been interrupted.
   *
   * @exception InterruptedException 
   */
  inline virtual void join() 
    throw(Synchronization_Exception) { }

  /**
   * Block until this executor has become available to run new tasks.
   *
   * This does not guarantee that another thread won't have submitted a
   * task before some action is taken in response to this. However, it
   * is useful as a general heuristic
   *
   * @return boolean
   * @exception InterruptedException 
   */
  virtual bool available() 
    throw(Synchronization_Exception) {
      
    Guard<LOCK> g(_lock);
    return !_canceled;

  }

  /**
   * Count of active threads operation on behalf of this executor
   *
   * This does not guarantee that another thread won't have submitted a
   * task that changes the number of executing threads before some action 
   * is taken in response to this. However, it is useful as a general 
   * heuristic
   * 
   * @return unsigned int
   * @exception InterruptedException 
   */ 
  virtual unsigned int threadCount()
    throw(Synchronization_Exception) {

    Guard<LOCK> g(_lock);
    return (!_canceled) ? 1 : 0;

  }


};

};

#endif
