/*
 * Copyright (c) 2005, Eric Crahen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef __ZTTHREAD_H__
#define __ZTTHREAD_H__

#include "zthread/Cancelable.h"
#include "zthread/Priority.h"
#include "zthread/NonCopyable.h"
#include "zthread/Task.h"
#include "zthread/Waitable.h"

namespace ZThread {
  
  class ThreadImpl;
  
  /**
   * @class Thread
   * @author Eric Crahen <http://www.code-foo.com>
   * @date <2003-07-27T11:17:59-0400>
   * @version 2.3.0
   *
   *
   * @see Task
   * @see Executor
   *
   * <h2>Examples</h2>
   * - <a href="#ex1">Launching a task</a>
   * - <a href="#ex2">Waiting for a task</a>
   * - <a href="#ex3">Sharing a task</a>
   *
   * <h2><a name="ex1">Launching a task</a></h2>
   *
   * A thread is started simply by constructing a thread object and giving 
   * it a task to perform. The thread will continue to run its task, even 
   * after the Thread object used to launch the thread has gone out of scope.
   *
   * @code
   * #include "zthread/Thread.h"
   * #include <iostream>
   *
   * using namespace ZThread;
   *
   * class aRunnable : public Runnable {
   *
   *   void run() {
   *
   *     Thread::sleep(1000);
   *     std::cout << "Hello from another thread" << std::endl;
   *
   *   }
   *
   * };
   *
   * int main() {
   *
   *   try {
   *     
   *     // Implictly constructs a Task
   *     Thread t(new aRunnable);
   *
   *   } catch(Synchronization_Exception& e) { 
   *     std::cerr << e.what() << std::endl; 
   *   }
   *
   *   std::cout << "Hello from the main thread" << std::endl;
   *
   *   // Output:
   *
   *   // Hello from the main thread
   *   // Hello from another thread
   *
   *   return 0;
   *
   * }
   *
   * @endcode
   *
   * <h2><a name="ex2">Waiting for a task</a></h2>
   *
   * A user can exercise some simple synchronization by waiting for a thread
   * to complete running its task.
   *
   * @code
   * #include "zthread/Thread.h"
   * #include <iostream>
   *
   * using namespace ZThread;
   *
   * class aRunnable : public Runnable {
   * public:
   *
   *   void run() {
   *
   *     Thread::sleep(1000);
   *     std::cout << "Hello from another thread" << std::endl;
   *
   *   }
   *
   * };
   *
   * int main() {
   *
   *   try {
   *     
   *     // Implictly constructs a Task
   *     Thread t(new aRunnable);
   *     t.wait();
   *
   *   } catch(Synchronization_Exception& e) { 
   *     std::cerr << e.what() << std::endl; 
   *   }
   *
   *   std::cout << "Hello from the main thread" << std::endl;
   *
   *   // Output:
   *
   *   // Hello from another thread
   *   // Hello from the main thread
   *
   *   return 0;
   *
   * }
   *
   * @endcode
   *
   * <h2><a name="ex3">Sharing a task</a></h2>
   *
   * The same task can be shared by more than one thread. A Task is constructed
   * from a Runnable, and that Task object is copied by value and handed off to
   * each thread.
   *
   * @code
   * #include "zthread/Thread.h"
   * #include <iostream>
   *
   * using namespace ZThread;
   *
   * class aRunnable : public Runnable {
   *
   *   void run() {
   *
   *     Thread::sleep(1000);
   *     std::cout << "Hello from another thread" << std::endl;
   *
   *   }
   *
   * };
   *
   * int main() {
   *
   *   try {
   *     
   *     // Explictly constructs a Task
   *     Task task(new aRunnable);
   *
   *     // Two threads created to run the same Task
   *     Thread t1(task);
   *     Thread t2(task);
   *
   *   } catch(Synchronization_Exception& e) { 
   *     std::cerr << e.what() << std::endl; 
   *   }
   *
   *   std::cout << "Hello from the main thread" << std::endl;
   *
   *   // Output:
   *
   *   // Hello from the main thread
   *   // Hello from another thread
   *   // Hello from another thread
   *
   *   return 0;
   *
   * }
   *
   * @endcode
   */
  class ZTHREAD_API Thread 
    : public Cancelable, public Waitable, public NonCopyable {

    //! Delegate
    ThreadImpl* _impl;

  public:

    /**
     * Create a Thread that represents the current thread.
     * <em>Using the static members of Thread should be preferred over using this constructor</em>
     */
    Thread();

    /**
     * Create a Thread that spawns a new thread to run the given task.
     *
     * @param task Task to be run by a thread managed by this executor 
     * @param autoCancel flag to requestion automatic cancellation
     *
     * @post if the <i>autoCancel</i> flag was true, this thread will
     *       automatically be canceled when main() goes out of scope.
     */
    Thread(const Task&, bool autoCancel = false);

    //! Destroy the Thread
    ~Thread();

    //! Comparison operator
    bool operator==(const Thread& t) const;

    //! Comparison operator
    inline bool operator!=(const Thread& t) const {
      return !(*this == t);
    }

    /**
     * Wait for the thread represented by this object to complete its task.
     * The calling thread is blocked until the thread represented by this
     * object exits.
     *
     * @exception Deadlock_Exception thrown if thread attempts to join itself
     * @exception InvalidOp_Exception thrown if the thread cannot be joined
     * @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed
     */
    void wait();
 
    /**
     * Wait for the thread represented by this object to complete its task.
     * The calling thread is blocked until the thread represented by this
     * object exits, or until the timeout expires.
     *
     * @param timeout maximum amount of time (milliseconds) this method 
     *        could block the calling thread.
     *
     * @return 
     *   - <em>true</em> if the thread task complete before <i>timeout</i> 
     *     milliseconds elapse.
     *   - <em>false</em> othewise.
     *
     * @exception Deadlock_Exception thrown if thread attempts to join itself
     * @exception InvalidOp_Exception thrown if the thread cannot be joined
     * @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed
     */
    bool wait(unsigned long timeout);
 
    /**
     * Change the priority of this Thread. This will change the actual
     * priority of the thread when the OS supports it. 
     *
     * If there is no real priority support, it's simulated.
     *
     * @param p - new Priority
     */
    void setPriority(Priority p);

    /**
     * Get the priority of this Thread.
     *
     * @return Priority
     */
    Priority getPriority();

    /**
     * Interrupts this thread, setting the <i>interrupted</i> status of the thread.
     * This status is cleared by one of three methods. 
     *
     * If this thread is blocked when this method is called, the thread will
     * abort that blocking operation with an Interrupted_Exception.
     *
     *  - The first is by attempting an operation on a synchronization object that
     *    would normally block the calling thread; Instead of blocking the calling 
     *    the calling thread, the function that would normally block will thrown an
     *    Interrupted_Exception and clear the <i>interrupted</i> status of the thread.
     *
     *  - The second is by calling Thread::interrupted().
     * 
     *  - The third is by calling Thread::canceled().
     *
     * Threads already blocked by an operation on a synchronization object will abort
     * that operation with an Interrupted_Exception, clearing the threads <i>interrupted</i>
     * status as in the first case described above.
     *
     * Interrupting a thread that is no longer running will have no effect.
     *
     * @return 
     *   - <em>true</em> if the thread was interrupted while not blocked by a wait
     *     on a synchronization object.
     *   - <em>false</em> othewise.
     */
    bool interrupt();

    /**
     * Tests whether the current Thread has been interrupt()ed, clearing
     * its interruption status.
     *
     * @return 
     *   - <em>true</em> if the Thread was interrupted.
     *   - <em>false</em> otherwise.
     *
     * @post The <i>interrupted</i> status of the current thread will be cleared, 
     *       allowing it to perform a blocking operation on a synchronization
     *       object without throwing an exception.
     */
    static bool interrupted();

    /**
     * Tests whether the current Thread has been canceled, and clears the
     * interrupted status.
     *
     * @return bool true only if the Thread::cancel() has been invoked.
     */
    static bool canceled();

    /**
     * Tests whether this thread has been canceled. If called from the context
     * of this thread, the interrupted status is cleared.
     *
     * @return 
     *   - <em>true</em> if the Thread was canceled.
     *   - <em>false</em> otherwise.
     * 
     * @see Cancelable::isCanceled()
     */
    virtual bool isCanceled();

    /**
     * Interrupt and cancel this thread in a single operation. The thread will 
     * return <em>true</em> whenever its cancelation status is tested in the future.
     *
     * @exception InvalidOp_Exception thrown if a thread attempts to cancel itself
     *
     * @see Thread::interrupt()
     * @see Cancelable::cancel()
     */
    virtual void cancel();

    /**
     * Put the currently executing thread to sleep for a given amount of
     * time.
     *
     * @param timeout maximum amount of time (milliseconds) this method could block
     *
     * @exception Interrupted_Exception thrown if the threads sleep is interrupted
     *            before <i>timeout</i> milliseconds expire.
     */
    static void sleep(unsigned long timeout);

    /**
     * Cause the currently executing thread to yield, allowing the scheduler
     * to assign some execution time to another thread.
     */
    static void yield();


  }; /* Thread */


} // namespace ZThread

#endif // __ZTTHREAD_H__



