/* clock.h */

#ifndef CLOCK__H
#define CLOCK__H

#include "timed.h"
#include "id.h"

struct dc_link; /* defined in link.h */
struct dc_element;
struct dc_component;

// struct s_clk_item {
//   dc_label *l; /* component or element */
//   list_item clk_loc; /* location of clock in l's secondary_clocks list */
// };

/* - dc_clock handle updating/reseting of all objects in hierarchy
   - clocked objects include
   -   descendants of dc_timed
   -     dc_clock
   -     dc_component
   -     dc_element
   -   dc_link
   - clocked objects have a main clock and a clock dependancy list
   -   when the main clock is advanced a full update occurs
   -     elements push value into old_value and put new_value into value
   -     components call update and links call exec
   -     clocks call advance
   -     all last update times are set to the current time
   -   when a dependancy of an object occurs
   -     elements override value with new value but do not change old_value
   -     last update times are not changed
   */
class dc_clock : public dc_label {
private:
  /* on reset, interval will be reset to initial_interval */
  double initial_interval;

  /* amount clock will be advanced per step.  if an advances of 10 time units is
     called and the interval is two, 5 advances of 2 time units ea. will be 
     executed */
  double interval;

  /* current time */
  double time;

  /* time since last update.  will be 0 if still at time 0 or <= interval */
  double delta_time;

  /* list of objects which have this as their main clock - updated */
  list<dc_label *> main_targets;

  /* list of objects refreshed by this clock */
  list<dc_label *> secondary_targets;

  /* list of links that have to be execed by this clock */
  list<dc_link *> links;

  /* list of clocks advanced by this clock */
  list<dc_clock *> clocks;
  
  /* reverse list - clocks that advance this clock */
  list<dc_clock *> rev_clocks;

  /* location in global list of clocks */
  list_item global_entry;

protected:
  /* called by advance, so must not advance time */
  virtual bool update( void ) { return false; }
  dc_clock( void );

public:
  dc_clock( cstring, dc_node *parent = nil, double = 1 );
  
  /* destructor does not delete targets.  targets will be unclocked */
  ~dc_clock( void );

  const dc_type type( void ) const { return Clock_t; }
  string type_string( void ) const { return string( "clock" ); }

  /* - advances time
     -   calls update on itself which is virtual function inherited from dc_time
         which can be used to control interval or perform other actions in
	 derived clock classes
     -   updating all target elements and components, advancing all target 
         clocks, and executes all target links.
     -   calls semi-update on all dependant elements
     */
  double advance( void ); /* advance by interval */
  double advance( double d ); /* advance by d in ciel( d/interval ) steps */
  virtual void reset( void ); /* reset clocks and all dependencies */

  double t( void ) const { return time; } /* get time */
  double dt( void ) const { return delta_time; } /* get change in time since
						    targets last updated */
  double get_interval( void ) const { return interval; }
  double get_initial_interval( void ) const { return initial_interval; }
  void set_interval( double i ) { interval = i; }
  void init_interval( double i ) { initial_interval = i; }

  /* used to add objects to this clock making this their main clock */
  bool add( dc_label & );
  bool remove( dc_label & );
  bool add( dc_link & );
  bool remove( dc_link & );
  bool add( dc_clock & );
  bool remove( dc_clock & );

  /* makes this clock the labels secondary clock */
  bool add_secondary( dc_label & );
  bool remove_secondary( dc_label & );

  dc_label *duplicate( dc_node *parent ) const;

  friend dc_element;
  friend dc_component;
};

/* resets all clocks in the hierarchy */
void reset_all( void );

#endif
