#ifndef __ZTSYNCRHONIZED_H__
#define __ZTSYNCRHONIZED_H__

#if defined(_WIN32)
#include "Win32_ThreadImpl.h"
#elif _POSIX
#include "POSIX_ThreadImpl.h"
#endif


namespace ZThread {

/**
 * @class Synchronized
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-06T07:30:40-0500>
 *
 * Has some of the repetative code the three basic Synchronized use - mostly
 * setting and checking various state flags.
 */
class Synchronized {
 protected:
  
  typedef ThreadImpl::MONITOR MONITOR;

 public:

  virtual ~Synchronized() throw() { }

  /**
   * Get the state Monitor for the currently executing thread.
   *
   * @return MONITOR&
   */
  inline MONITOR& getMonitor() const 
    throw(Synchronization_Exception) {

    // Get a reference to the state Monitor used to control this thread.
    ThreadImpl* self = ThreadImpl::current();
    return self->getMonitor();
    
  }

  /**
   * Given a Monitor for some thread, get the interesting state bits
   * (INTERRUPTED, JONED, KILLED and SIGNAL). 
   *
   * The INTERRUPTED bit is only cleared when SIGNAL is not present.
   * The SIGNAL bit is always cleared if set.
   *
   * @param Monitor
   * @return relevant state bits
   * 
   * @pre The caller should own the lock on the Monitor
   */
  inline unsigned int check(MONITOR& e) 
    throw(Synchronization_Exception) {

    // Mask for the interesting state bits
    unsigned int mask = (State::INTERRUPTED|State::JOINED|State::KILLED|State::SIGNAL);
    unsigned int state = e->state() & mask;
    
    // Check the SIGNAL bit, clear it if set. Preferring the SIGNAL over the 
    // INTERRUPTED flag prevents lost signals.
    if(!e->toggle(State::SIGNAL)) 
      e->toggle(State::INTERRUPTED); // Check the INTERRUPTED bit, clear it if set
    
    return state;

  }

  /**
   * Given a Monitor, check the interesting state bits, if none are 
   * set then set the SIGNAL bit.
   *
   * @param Monitor
   * @return bool true if the bit was set, false if not.
   *
   * @pre The caller should own the lock on the Monitor
   */
  inline bool wake(MONITOR& e) {

    unsigned int mask = (State::INTERRUPTED|State::JOINED|State::KILLED|State::SIGNAL);
    unsigned int state = e->state() & mask;

    if(state)
      return false;

    // Set the bit & wake the thread
    e->set(State::SIGNAL);
    return true;
    
  }

};

};

#endif
