/* link.h */

#ifndef LINK__H
#define LINK__H

#include <LEDA/list.h>
#include <LEDA/graph.h>
#include <iostream.h>
#include "component.h"
#include <LEDA/graph_alg.h>
#include "clock.h"

/* see cor_syn_iface.h for physical link types */
enum dc_link_type { Undef_lt = 0, Base_lt, 
		    Physical_lt, Distance_lt, Axial_lt, Attachment_lt, Force_lt,
		    Electrical_lt };

/* indexed by dc_link_type */
const char *const dc_lt_string[] = { "generic", "link",
				     /* physical_links */
				     "physical", "dist", "axial",
				     "attachment", "force",
				     /* other types of links, not used yet */
				     "electrical" };

class dc_link /* : public dc_common */ {
protected:
  /* link fixed at an end if hash string is "".  otherwise will relink on 
     rehashes */
  string hash_source;
  string hash_target;
  string hash_clock;
  dc_label *hash_origin;

private:
  edge lgraph_edge;
  edge lgraph_rev_edge; /* nil if directed */

  /* true if link goes from source to target.  false if link goes both ways */
  bool directed;
  list_item lol_pos; /* position in global list of links */

  dc_clock *clock;
  list_item clk_entry;
public:
  dc_link( void );
  virtual ~dc_link( void );

  virtual const dc_link_type type( void ) const { return Base_lt; }

  /* evaluate link.  returns true on failure */
  virtual bool exec( void ) { return false; }

  void set_clock_info( cstring s ) { hash_clock = s; }

  void set_hash_info( cstring source, cstring target, dc_label *origin ) {
    hash_source = source; hash_target = target; hash_origin = origin; }

  bool set_ends( dc_component &, dc_component & );

  /* called by set_ends.  if init returns true then edge will be deleted and 
     add_edge will return nil */
  virtual bool init( void ) { return false; }

  int relink( void );
  virtual int rehash( void ) { return relink(); } /* returns number of errors */

  virtual ostream &display( ostream & = cout ) const;

  dc_component *get_source( void ) const;
  dc_component *get_target( void ) const;

  /* will not take effect until next rehash */
  void set_directed( bool d ) { directed = d; }

  bool get_directed( void ) const { return directed; }

  friend void forall_links( void ( dc_link &, void * ), void * );
  friend class dc_clock;
};

inline ostream &operator<<( ostream &stream, const dc_link &l ) {
  return l.display( stream );
}

typedef GRAPH<dc_component *, dc_link *> lgraph; /* linkage graph */

extern lgraph link_graph;

/* WARNING - CREATING AN EDGE FROM A COMPONENT TO ITSELF WILL CAUSE EDGES TO BE 
   DELETED TWICE */
dc_link *add_link( dc_component &src, dc_component &dest,
		   dc_link_type type = Base_lt, bool directed = false );
dc_link *add_link( cstring src, cstring dest, dc_label *origin,
		   dc_link_type type = Base_lt, bool directed = false );
dc_link *add_link( cstring src, dc_label *origin, dc_link_type type = Base_lt, 
		   bool directed = false );

void forall_links( void ( dc_link &, void * ), void * );

void display_links( ostream & = cout );

void clear_link_graph( void ); /* called by root dealloc to remove all links
				  before */

#endif
