// file: $isip/class/asr/Identifier/ident_05.cc
// version: $Id: ident_05.cc 7678 2002-02-01 14:49:32Z alphonso $
//

// isip include files
//
#include "Identifier.h"

// method: clear
//
// arguments:
//   Integral::CMODE cmode: (input) clear mode
//
// return: logical error status
//
// this method clears the content of the current object
//
boolean Identifier::clear(Integral::CMODE cmode_a) {

  // declare local variables
  //
  boolean status = false;
  
  status = namespace_d.clear(cmode_a);
  status &= type_d.clear(cmode_a);
  status &= issued_d.clear(cmode_a);
  status &= curr_d.clear(cmode_a);
  status &= anchors_d.clear(cmode_a);
  status &= annotations_d.clear(cmode_a);

  // return the ;ogical status
  //
  return status;  
}

// method: eq
//
// arguments:
//   const Identifier& arg: (input) annotation graph
//
// return: logical error status
//
// method determines if the input identifier is equal to the current
//
boolean Identifier::eq(const Identifier& arg_a) const {

  // determine if the member data are equal
  //
  if (!namespace_d.eq(arg_a.namespace_d)) {
    return false;
  }
  if (!type_d.eq(arg_a.type_d)) {
    return false;
  }
  if (!issued_d.eq(arg_a.issued_d)) {
    return false;
  }
  if (!curr_d.eq(arg_a.curr_d)) {
    return false;
  }
  if (!anchors_d.eq(arg_a.anchors_d)) {
    return false;
  }
  if (!annotations_d.eq(arg_a.annotations_d)) {
    return false;
  }

  // return the logical status
  //
  return true;
}

// method: assign
//
// arguments:
//   const Identifier& arg: (input) annotation graph
//
// return: logical error status
//
// method assigns the input identifier to the current one
//
boolean Identifier::assign(const Identifier& arg_a) {

  // declare local variables
  //
  boolean status = false;
  
  status = namespace_d.assign(arg_a.namespace_d);
  status &= type_d.assign(arg_a.type_d);
  status &= issued_d.assign(arg_a.issued_d);
  status &= curr_d.assign(arg_a.curr_d);
  status &= anchors_d.assign(arg_a.anchors_d);
  status &= annotations_d.assign(arg_a.annotations_d);

  // return the ;ogical status
  //
  return status;
}

// method:: registerId
//
// arguments: none
//
// return: registered identifier
//
// method to try to register a new identifier
//
const String Identifier::registerId() {

  // declare local variables
  //
  String id;
  String buffer;

  // assign the highest id issued so far to the buffer
  //
  buffer.assign(curr_d);

  // generate a new identifier
  //
  if (namespace_d.eq(String::EMPTY)) {
    id.assign(type_d);
    id.concat(buffer);
  } else {
    id.assign(namespace_d);
    id.concat(L":");
    id.concat(type_d);
    id.concat(buffer);
  }

  // make sure the new identifier was not already issued
  //
  while (issued_d.contains(&id)) {

    curr_d++;
    buffer.assign(curr_d);

    // generate a new identifier
    //    
    if (namespace_d.eq(String::EMPTY)) {
      id.assign(type_d);
      id.concat(buffer);
    } else {
      id.assign(namespace_d);
      id.concat(L":");
      id.concat(type_d);
      id.concat(buffer);
    }
  }

  // add the id to the list of issued identifiers
  //
  issued_d.insert(&id);
  
  // return the registered identifier
  //
  return id;
}

// method: registerId
//
// arguments:
//   const String& id: (input) identifier
//
// return: registered identifier
//
// method to try to register the given identifier
//
const String Identifier::registerId(const String& id_a) {

  // declare local variables
  //
  String id;
  id.assign(id_a);
  
  // check if the namespace of the identfier and the given id agree
  //
  if(!namespace_d.eq(getNamespace(id))) {
    return Error::handle(name(), L"registerId", Error::ARG, __FILE__, __LINE__);
  }

  // check if the identifier has been issued
  //
  if (issued_d.contains(&id)) {

    // return the new registered id
    //
    return registerId();
  }
  
  // otherwise just insert the given id
  //
  issued_d.insert(&id); 

  // return the given registered id
  //
  return id;
}

// method: existsId
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to check if an id has been issued
//
boolean Identifier::existsId(const String& id_a) {
  return issued_d.contains(&id_a);
}

// method: reclaimId
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to reclaim an id
//
boolean Identifier::reclaimId(const String& id_a) {

  // remove the id from the list
  //
  if (issued_d.find(&id_a)) {
    issued_d.remove();
  }
  
  // exit gracefully
  //
  return true;  
}

// method: getNamespace
//
// arguments:
//   const String& id: (input) identifier
//
// return: namespace of the identifier
//
// method to get the namespace of the id
//
String Identifier::getNamespace(const String& id_a) {

  // declare local variables
  //
  long pos;
  String output;
  
  // find the position of the first delimiter in the id
  //
  pos = id_a.firstChr(L":");

  // return an empty string if no delimiters are present
  //
  if (pos == Integral::NO_POS) {
    return String::EMPTY;
  }

  // return the substring corresponding to the namespace
  //
  if (!id_a.substr(output, 0, pos)) {
    return Error::handle(name(), L"getNamespace", Error::ARG, __FILE__, __LINE__);
  }
  return output;
}

// method: getAnnotationRef
//
// arguments:
//   const String& id: (input) identifier
//
// return: annotation
//
// method to get the annotation reference by id
//
Annotation* Identifier::getAnnotationRef(const String& id_a) {

  // declare local variables
  //
  Annotation* annotation = (Annotation*)NULL;

  // determine if the key was hashed
  //
  if (annotations_d.containsKey(id_a)) {
    annotation = annotations_d.get(id_a);
  }
  
  // return the annotation
  //
  return annotation;
}

// method: getAnchorRef
//
// arguments:
//   const String& id: (input) identifier
//
// return: anchor
//
// method to get get the anchor reference by id
//
Anchor* Identifier::getAnchorRef(const String& id_a) {

  // declare local variables
  //
  Anchor* anchor = (Anchor*)NULL;

  // determine if the key was hashed
  //
  if (anchors_d.containsKey(id_a)) {
    anchor = anchors_d.get(id_a);
  }
  
  // return the anchor
  //
  return anchor;  
}

// method: deleteAnnotationRef
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to delete a annotation id to reference mapping
//
boolean Identifier::deleteAnnotationRef(const String& id_a) {

  // remove the id from the hash table
  //
  return annotations_d.remove(id_a);  
}  

// method: deleteAnchorRef
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to delete a anchor id to reference mapping
//
boolean Identifier::deleteAnchorRef(const String& id_a) {

  // remove the id from the hash table
  //
  return anchors_d.remove(id_a);    
}

// method: addAnnotationRef
//
// arguments:
//   const String& id: (input) identifier
//   Annotation* ref: (input) annotation
//
// return: logical error status
//
// method to add a annotation id to reference mapping
//
boolean Identifier::addAnnotationRef(const String& id_a, Annotation* ref_a) {

  // insert the id into the hash table
  //
  return annotations_d.insert(id_a, ref_a);  
}  

// method: addAnchorRef
//
// arguments:
//   const String& id: (input) identifier
//   Anchor* ref: (input) anchor
//
// return: logical error status
//
// method to add a anchor id to reference mapping
//
boolean Identifier::addAnchorRef(const String& id_a, Anchor* ref_a) {

  // insert the id into the hash table
  //
  return anchors_d.insert(id_a, ref_a);  
}  

// method: existsAnnotation
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to check if a annotation exists
//
boolean Identifier::existsAnnotation(const String& id_a) {

  // determine if the id exists in the hash table
  //
  return annotations_d.containsKey(id_a);  
}  

// method: existsAnchor
//
// arguments:
//   const String& id: (input) identifier
//
// return: logical error status
//
// method to check if a anchor exists
//
boolean Identifier::existsAnchor(const String& id_a) {

  // determine if the id exists in the hash table
  //
  return anchors_d.containsKey(id_a);    
}  
