/* id.h */

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

#ifndef ID__H
#define ID__H

/* - dc_labels contain a unique tag, a string label, and a parent.  global lists
   are kept at the root( see root.h ) that map tags to pointers.  
   - dc_labels do not have children themselves, but a descendant class dc_node 
   has a list mapping local_labels to pointers to children.
   - the root also has a list mapping local_labels to pointers to root objects.

   - all channges to the hierarchy should be made using member fns set_label, 
   set_parent, and set_both.  set_both should be used when setting both label 
   and parent to avoid label conflicts in intermediate state.

   - lookup functions use a path of the form "labela.labelb.labelc".
   - valid labels are strings of any characters except '.'.
   - the parser further restricts labels to be strings starting with an 
   underscore or alphabet character, and any following characters must be
   alphanumeric or underscores.
   - there must be no conflicts between labels. dc_nodes cannot have two 
   children with the same label, and two root objects cannot have the same label

   - all non-temporary dc_labels and descendants of dc_label must be 
   dynamically allocated because all are contained in a tag list at the root 
   which is used for cleanup on exit, rehash or reset   
*/

/* separates ancestor labels in globalLabel */
const char ID_SEPARATOR = '.';
const string ID_SEP_STRING = string( ID_SEPARATOR );

/* given two labels diff_lbl returns position in src_lbl directly after 
   separator before first non-matching local-label.
   ex. diff_lbl( "any.other.thing.which", ".any.other.think.how.to" ) 
   returns 11.  position of 't' in 'thing' from src_lbl.
   
   since preceding '.''s are optional, position is not necessarily the position
   of the corresponding '.' in other.
   
   if both are same, return value will be the last . or 0 */
int diff_lbl( cstring src_lbl, cstring other );

struct dc_node;
struct base_hook;

class dc_label : public dc_common {
private:
  tag globalTag; /* unique integer assigned at creation or on first call to 
		    set_label/set_parent/set_both.  see tag.h */
  string localLabel; /* only "" if temporary */
  dc_node *parentId; /* if non-temporary and  parent is nil, then object exists
			at root */

  /* temporary objects do not appear in hierarchy, and are deleted after being
     used in an operation.  most objects - nodes, components, elements are made
     permanent in constructor */
  bool temporary;
  
  /* invisible labels will not appear in hierarchy searches unless see_all flag
     specifically set in call to search */
  bool visible;

  /* templated objects are duplicated from a template and inserted into a node 
     or component.

     this list_item is set by duplicate function so that inherited objects can 
     all be removed at rehash time and reduplicated. */
  list_item templated;

protected:
  dc_label( void ); /* created as temporary */
  
public:
  /* I -- FUNCTIONS TO CREATE LABELS or SUB_TYPES */
  /* NOTE -- all instances of dc_label, and its derived classes must be 
     dynamically allocated since cleanup an deallocation of temporaries is done
     automatically */
  virtual ~dc_label();

  /* II -- FUNCTIONS TO MANIPULATE LABEL HIERARCHY
     - all three return true on failure*/
  /* changes label, or if temporary places at root with new_label */
  bool set_label( cstring new_label ); 

  /* removes this from old parent or root and adds to parent or root. */
  bool set_parent( dc_node *parent );

  /* combines set_label and set_parent to avoid label conflicts in intermediate
     state that can result from calling both */
  bool set_both( cstring label, dc_node *parent );

  /* IV -- INHERITED TYPE FUNCTIONS */
  const dc_type type( void ) const { return Label_t; }
  string type_string( void ) const { return string( "label" ); }

  /* V -- FUNCTIONS FOR ACCESSING PROTECTED/PRIVATE MEMEBRS */
  /* returns full label by appending local label to parent's label.
     if temporary returns "" */
  string label( void ) const;

  /* returns label of parent or '.' as appropriate */
  string parent_label( void ) const;
  string local_label( void ) const { return localLabel; }

  /* compares label with a given string.
     avoids copying label to string caused by local_label() == s */
  bool match_label( cstring s ) const { return localLabel == s; }

  /* returns string of the form
     type_string:"full_label" or if temporary just type_string */
  string full_type( void ) const;
  dc_node *get_parent( void ) const { return parentId; }
  tag get_tag( void ) const { return globalTag; }
  bool is_temporary( void ) const { return temporary; }

  bool is_templated( void ) const { return (templated != nil); }
  void set_templated( bool ti );

  /* VI -- MISC & DEBUGGING FUNCTIONS */
  ostream &display( ostream &stream = cout );
  friend ostream &operator<<( ostream &stream, dc_label &ID ) {
    return ID.display( stream );
  }

  inline void set_visible( const bool v = true );
  virtual void set_visible_i( const bool v ) { set_visible( v ); }

  bool is_visible( void ) const { return visible; }

  virtual const bool is_data( void ) const { return true; } 

  virtual dc_label *duplicate( dc_node *parent ) const = 0;

  /* allows additional info to be associated with an object 
     see signal_change.h and gui_jooh.h */
  base_hook *hook;
};

/* perform an operation on all descendants of orign including origin that match
   the given criterion */
void for_desc_match( bool ( dc_label * ), dc_label *, 
		     void ( dc_label * ), const bool see_all = false );
void for_desc_match( bool ( dc_label *, void * ), dc_label *, 
		     void ( dc_label *, void * ), void *, 
		     const bool see_all = false );

/* perform an operation on all ids that match a given criterion */
void for_all_match( bool ( dc_label * ), void ( dc_label * ),
		    const bool see_all = false );
void for_all_match( bool ( dc_label *, void * ), void ( dc_label *, void * ), 
		     void *, const bool see_all = false );
void for_root_match( bool criterion( dc_label * ), void op( dc_label * ), 
		     const bool see_all = false );
void for_root_match( bool criterion( dc_label *, void * ), 
		     void op( dc_label *, void * ), const void *veep, 
	             const bool see_all = false );
void for_type_match( bool criterion( dc_label * ), dc_label *origin, 
		     user_type u_type, void op( dc_label * ), 
	             const bool see_all = false );
void for_type_match( bool criterion( dc_label *, void * ), dc_label *origin, 
	             user_type u_type, void op( dc_label *, void * ), 
	             void *veep, const bool see_all = false );

#endif
