/*
 *  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 __ZTWORKER_H__
#define __ZTWORKER_H__

#include "zthread/ZThread.h"
#include "zthread/Thread.h"

#include <assert.h>

namespace ZThread {

/**
 * @class Worker
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-02T22:35:30-0500>
 * @version 1.5.2
 *
 * A template for generating Worker threads that are designed for work in
 * Executors. They can be useful anywhere a group of worker threads that 
 * feed on a shared TaskQueue is needed. 
 *
 * In addition the template provides specializations for task consuming
 * or task reading workers. A consuming worker destroys tasks it has
 * executed, otherwise it simply executes the task and makes no attempt 
 * to destroy that task.
 */
template <bool CONSUMING=true, class Q=Queue<Runnable*> >
class ZTHREAD_API Worker : public Thread {

  protected:
  //! Typedef
  typedef Q* TaskQueue;

  //! TaskQueue
  TaskQueue _taskQueue;
  //! Cancel flag
  bool _canceled;

  public:

  /**
   * Create an AsyncWorker associated with a TaskQueue
   */
  Worker(TaskQueue q) throw(Synchronization_Exception) 
    : _taskQueue(q), _canceled(false) {
  }

  /**
   * Destroy the AsyncWorker
   */
  virtual ~Worker() throw() {
  }
  
  /**
   * Mark the thread as killed w/o actuallying kill()ing it and 
   * therefore w/o interefering with any task already executing
   */
  virtual void kill()
    throw(Synchronization_Exception) {

    _canceled = true;

  }

  /**
   * Check the internal flag to see if this Worker has been killed; or
   * marked as no longer usable
   *
   * @return bool - cancelation status
   */
  virtual bool isKilled()
    throw() {

    return _canceled;

  }

  /**
   * Tasks will be executed and removed from the queue. Wether or
   * not those tasks are deleted depends on the template parameter.
   */
  virtual void run() throw() {

    try {
     
      while(!_canceled) { // Pull tasks from queue until cancled
        
        Runnable* task = (Runnable*)_taskQueue->next();
        
        if(task) {
          
          task->run();
          finished(task);
          
          Thread::yield(); 
          
        }
        
      }
      
    } catch(Cancelation_Exception&) {

      /* Queue canceled */
      //ZTDEBUG("Worker exiting, queue was canceled\n");

    } catch(Unexpected_Exception&) {

      /* Worker killed */
      //ZTDEBUG("Worker exiting, worker was killed\n");

    } catch(Synchronization_Exception&) {
      
      /* Some other exception was thrown */
      assert(0);
      
    } catch(...) {
      
      //ZTDEBUG("Unexpected exception was caught\n");
      assert(0); // Should not occur, tasks should not throw
    }
    

  }

  
  protected:
  
  /**
   * As each task is completed, it is passed into this method to
   * properly deal with its completion. This function will destroy
   * the taks objects of a consuming worker, otherwise it has no effect.
   *
   * @post The task passed to this method will be delete'd or not 
   * depending on the nature of this Worker
   */
  void finished(Runnable*);

};


//
// Tasks are executed & removed from the TaskQueue - but NOT deleted
//
inline void Worker<false>::finished(Runnable* task) {
  // Do nothing to the task
}

//
// Delete tasks as they are executed is the default behaviour.
//
inline void Worker<true>::finished(Runnable* task) {
  delete task;
}


};

#endif
