/* timed.h */

#ifndef TIMED__H
#define TIMED__H

#include "common.h"
#include "tag.h"
#include <LEDA/list.h>

struct dc_clock; /* defined in clock.h */

unsigned char enum dc_status { Active_s = 0, Dormant_s = 1, Frozen_s = 2,
			       Dormant_Frozen_s = 3 };

/* mapped into by dc_status */
const char * const dc_status_string[] = { "active", "dormant", "frozen",
					  "dormant_frozen" };

/* compare functions for LEDA lists */
inline int compare( dc_label *const &a, dc_label *const &b ) {
  return (long int)a - (long int)b; }
inline int compare( dc_clock *const &a, dc_clock *const &b ) {
  return (long int)a - (long int)b; }

/* CLOCKED OBJECT STATUS
   an ACTIVE object can be updated, queried, rehahsed, etc. as normal
   a FROZEN object can be queried, but not updated or rehashed
   a DORMANT object exists but cannot be queried, updated or rehashed
   an object can be frozen and dormant in which case it is treated as dormant
       until made non-dormant when it is just frozen

   STATUS INHERITENCE
   when an object is frozen or made dormant all children of it are frozen or
   dormant.  status of a sub-object can then be changed affecting only it and
   its sub-objects.
   
   INHERITANCE RULES
   set_dormant( true ) - it is dormant, and all sub-objects not previously
                         dormant inherit their dormancy from it
   set_dormant( false ) - it and all objects that inherit their dormancy
                          from it are now non dormant
   
   set_frozen( true ) - only a components direct elements inherit the frozen 
                        status unless they were previously frozen
   freeze_all( void )- all descendants not previously frozen now inherit frozen
                       status from it.  not defined for elements
   set_frozen( false ) - all objects that inherit their frozen status are also
                         unfrozen

   HIERARCHY CHANGES
   if an object is frozen or dormant when it is moved in the hierarchy, its
   status is changed to non inherited
   */

/* abstract base class for any types that have to time_step and call 
   eval_functions including dc_clock, dc_component, and dc_element. 

   dc_links are also clocked but do not have frozen/dormant status so are 
   handled separately */
class dc_timed {
protected:
  double time; /* HOOOAH! Time last updated. time is relative to clock */

  dc_status status;
  tag frozen_inh; /* tag_error -> not inherited */
  bool dormant_inh; /* false -> not inherited */

  dc_clock *clock; /* primary clock */
  list_item clk_entry; /* location in clock's target_list */

  string clock_hash_lbl;
  dc_label *clock_hash_origin;

  list<dc_clock *> secondary_clocks;
public:
  dc_timed( void );
  
  virtual bool update( void ) = 0; /* true on error */
  virtual void reset( void ) { time = -1; }
  double get_time( void ) const { return time; }

  dc_status get_status( void ) const { return status; }
  bool is_dormant( void ) const { return status == Dormant_s ||
				         status == Dormant_Frozen_s; }
  bool is_frozen( void ) const { return status == Frozen_s ||
				   status == Dormant_Frozen_s; }

  /* allows clock to be rehashed */
  void set_clock_str( cstring s, dc_label *o = nil )
    { clock_hash_lbl = s; clock_hash_origin = o; }

  dc_clock *get_clock( void ) const { return clock; }
};

#endif
