/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2001 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 __ZTSTATE_H__
#define __ZTSTATE_H__

#include "zthread/ZThread.h"

namespace ZThread {

/**
 * @class State 
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-05T21:08:03-0500>
 *
 * Simple state object to encapsulate the details involved with setting 
 * and checking various bits, as well as some of the state transition 
 * logic.
 */
class State {
  
 public:

  enum {

    // Stage flags
    IDLE        = 0x01,
    RUNNING     = 0x02,
    JOINING     = 0x04,
    JOINED      = 0x08,
    KILLED      = 0x10,
    
    // Status flags
    INTERRUPTED = 0x01 << 8,
    REFERENCE   = 0x02 << 8,
    DAEMON      = 0x04 << 8,
    NOTIFY      = 0x08 << 8,

    // Monitor flags
    SIGNAL      = 0x10 << 8

  } STATE;

 private:

  unsigned int _flags;

  // Valid transition table
  static const unsigned int VALID[];

 public:

  /**
   * Create State with the IDLE flag set.
   */
  State() : _flags(IDLE) {}

  /**
   * Clear a flag, returning a bool indicating wether or not 
   * it was set. Only status bits can be cleared, stage bits 
   * can only be changed with a transition().
   *
   * @param flags
   * @return bool
   */
  inline bool clear(unsigned int flags) {

    // Mask out the stage bits
    flags &= (0xFF << 8);

    // Check the modifier flags
    bool result = (_flags & flags) != 0;
    _flags &= ~flags;

    return result;

  }

  /**
   * Check a flag, returning a bool indicating wether or not 
   * it was set.
   *
   * @param flags
   * @return bool
   */
  inline bool check(unsigned int flags) const {
    return (_flags & flags) != 0;
  }

  /**
   * Set the given modifier flags. Only status bits can be set,
   * stage bits can only be changed with a transition().
   *
   *
   * @param flags
   */
  inline void set(unsigned int flags) {
    
    // Mask out the stage bits
    flags &= (0xFF << 8);
    
    // Clear & set the modifier bits 
    _flags &= ~flags;
    _flags |= flags;
    
  }

  /** 
   * Get the state bits.
   *
   * @return unsigned int
   */
  inline unsigned int state() const {
    return _flags;
  }

  /**
   * Transition to a new state. Sets the correct state flag, 
   * returns true when the given transition is valid and is 
   * performed. Otherwise, false.
   *
   * @param flags
   * @return bool
   */
  inline bool transition(unsigned int flags) {

    // Convert the state flag into the a bit index
    unsigned int i=0;
    while((unsigned int)(1 << i) < (_flags & 0xFF))
      i++;

    // Check the transition table to make sure the
    // requested transition is valid.
    if(VALID[i] & flags) {
      
      // Update the state bits.
      _flags &= (0xFF << 8); 
      _flags |= flags;
      
      return true;

    }
    
    return false;
    
  }

  /**
   * Toggle some status flags off, returning a value indicating
   * if the flags were set before they were toggled off. Only status
   * bits can be toggle()d, stage bits can only be changed with a transition().
   *
   * @param flags
   * @return bool
   */
  inline bool toggle(unsigned int flags) {
    
    // Mask out the stage bits
    flags &= (0xFF << 8);

    bool result = (_flags & flags) != 0;
    _flags &= ~flags;

    return result;

  }

};


};

#endif
