/* pointer.cc */

#include "pointer.h"
#include "display.h"
#include "id_lookup.h"

static list<dc_pointer *> pointer_list;

dc_pointer::dc_pointer( void ) {
  list_loc = pointer_list.append( this );

  valid = false;
  val = nil;
  search_type = Label_t;
  search_origin = nil;
}

dc_pointer::dc_pointer( cstring path, dc_type T, dc_label *origin ) {
  list_loc = pointer_list.append( this );

  valid = false;
  val = nil;
  search_type = Label_t;
  set_origin( origin );
  set( path, T );
}

dc_pointer::dc_pointer( cstring label, dc_node *parent = nil ) {
  list_loc = pointer_list.append( this );

  valid = false;
  val = nil;
  search_type = Label_t;
  search_origin = nil;
  set_both( label, parent );
}

dc_pointer::dc_pointer( cstring path, dc_type T, dc_label *origin, 
			cstring label, dc_node *parent = nil ) {
  list_loc = pointer_list.append( this );

  valid = false;
  val = nil;
  search_type = Label_t;
  search_origin = nil;
  set_origin( origin );
  set( path, T );
  set_both( label, parent );
}

dc_pointer::~dc_pointer( void ) {
  pointer_list.del_item( list_loc );
}

dc_pointer &dc_pointer::operator=( const dc_pointer &P ) {
  val = P.val;
  search_path = P.search_path;
  search_type = P.search_type;
  valid = P.valid;
  return *this;
}

ostream &dc_pointer::display_c( ostream &stream = cout ) const {
  if( disp_as_parsed ) {
    return stream << "&" << search_path;
  }
  if( !valid ) {
    return stream << "<invalid>";
  } else if( val ) {
    return stream << "&" << val->label();
  }
  return stream << "<nil>";
}

void dc_pointer::set( cstring path, dc_type T ) {
  search_path = path;
  search_type = T;
  rehash();
}

void dc_pointer::set( cstring path ) {
  search_path = path;
  rehash();
}

int dc_pointer::rehash( void ) {
  if( !search_path.length() ) {
    val = nil;
    valid = true;
    return 0;
  }

  switch( search_type ) {
  case Undef_t : case Label_t :
    val = search( search_path, search_origin );
    break;
  default :
    val = t_search( search_path, search_type, search_origin );
  }

  if( val == nil || val->type() == Pointer_t ) {
    val = nil;
    valid = false;
    return 1;
  }
  return 0;
}

dc_label *dc_pointer::duplicate( dc_node *parent ) const {
  dc_pointer *dupe = new dc_pointer();
  dupe->set_origin( search_origin );
  dupe->set( search_path, search_type );

  if( !is_temporary() ) {
    if( dupe->set_both( local_label(), parent ) ) {
      delete( dupe );
      return nil;
    }
  }
  dupe->set_visible( is_visible() );
  return ( dc_label * )dupe;
}

int rehash_pointers( void ) {
  int nerrors = 0;
  dc_pointer *p;
  forall( p, pointer_list ) {
    nerrors += p->rehash();
  }
  return nerrors;
}
