// file: $isip/class/dstr/TreeNode/TreeNode.h
// version: $Id: TreeNode.h 8646 2002-08-23 01:06:43Z alphonso $
//

// make sure definitions are made only once
//
#ifndef ISIP_TREE_NODE
#define ISIP_TREE_NODE

// isip include files
//
#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_NODE
#include <Node.h>
#endif

#ifndef ISIP_CONSOLE
#include <Console.h>
#endif

// forward class definitions
//
template<class TObject> class TreeNodeDiagnose;

// TreeNode: this class implements a TreeNode data structure that forms the
// basis of the Tree class
//
template<class TObject>
class TreeNode : public Node<TObject> {
    
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String DEF_PARAM;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------
  
  // default values
  //
  static const long DEF_DEGREE = 0;
  
  // default arguments to methods
  //
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // define a pointer to the parent node
  //
  TreeNode<TObject>* parent_d;
  
  // define a pointer to the left child node
  //
  TreeNode<TObject>* left_d;

  // define a pointer to the right child node
  //
  TreeNode<TObject>* right_d;      

  // define the out degree of the node
  //
  Long degree_d;
  
  // debugging parameters
  //
  static Integral::DEBUG debug_level_d;

  // define the memory manager
  //  
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // static methods:
  //  the diagnose method is moved outside the class header file and
  //  defined in the TreeNodeDiagnose.h in order to avoid issues
  //  with preprocessing of the diagnose code.
  //
  static const String& name();
  
  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }

  // other debug methods
  //
  boolean debug(const unichar* msg) const;
     
  // destructor/constructor(s)
  //
  ~TreeNode();
  TreeNode(TObject* item = (TObject*)NULL);
  TreeNode(const TreeNode<TObject>& copy_tnode);

  // assign method
  //
  boolean assign(const TreeNode<TObject>& copy_stack);
  
  // method: operator=
  //
  TreeNode<TObject>& operator=(const TreeNode<TObject>& arg) {
    assign(arg);
    return *this;
  }

  // equality method
  //
  boolean eq(const TreeNode<TObject>& arg) const;
  
  // method: read
  //
  boolean read(Sof& sof, long tag) {
    return read(sof, tag, name());
  }

  // method: write
  //
  boolean write(Sof& sof, long tag) const {
    return write(sof, tag, name());
  }

  // method: sofSize
  //
  long sofSize() const {
    return 0;
  }

  // method: read
  //
  boolean read(Sof& sof, long tag, const String& name) {
    return Error::handle(name(), L"read", Error::ARG, __FILE__, __LINE__);
  }

  // method: write
  //
  boolean write(Sof& sof, long tag, const String& name) const {
    return Error::handle(name(), L"write", Error::ARG, __FILE__, __LINE__);
  }

  // method: readData
  //
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT,
                   boolean param = true,
		   boolean nested = true) {
    return Error::handle(name(), L"readData", Error::ARG, __FILE__, __LINE__);
  }

  // method: writeData
  //
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const {
    return Error::handle(name(), L"writeData", Error::ARG, __FILE__, __LINE__);
  }

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }
    
  // clear method
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  tree node manipulation methods
  //
  //---------------------------------------------------------------------------

  // method: degree
  //
  long degree() const {
    return (long)degree_d;
  }
  
  // method: increment
  //
  boolean increment() {
    degree_d = (long)degree_d + 1;
    return true;
  }

  // method: decrement
  //
  boolean decrement() {
    degree_d = (long)degree_d - 1;
    return true;
  }  
  
  // method: getParent
  //
  TreeNode<TObject>* getParent() const {
    return parent_d;
  }
  
  // method: setParent
  //
  boolean setParent(const TreeNode<TObject>* arg) {
    parent_d = const_cast<TreeNode<TObject>* >(arg);
    return true;
  }

  // method: getLeftChild
  //
  TreeNode<TObject>* getLeftChild() const {
    return left_d;
  }

  // method to set the left child of the node
  //
  boolean setLeftChild(const TreeNode<TObject>* arg);

  // method: getRightSibling
  //
  TreeNode<TObject>* getRightSibling() const {
    return right_d;
  }

  // method to set the right sibling of the node
  //
  boolean setRightSibling(const TreeNode<TObject>* arg);

  // node adjacency methods
  //
  boolean isAdjacent(const TObject* obj) const;    
  boolean isAdjacent(const TreeNode<TObject>* node) const;
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------

private:

  // declare friend classes
  //
  template <class TObject_diagnose> 
  friend class TreeNodeDiagnose;  
};

//-----------------------------------------------------------------------------
//
// we define non-integral constants at the end of class definition for
// templates (for non-templates these are defined in the default constructor)
//      
//-----------------------------------------------------------------------------

// constants: required constants such as the class name
//
template <class TObject>
const String TreeNode<TObject>::CLASS_NAME(L"TreeNode");

template <class TObject>
const String TreeNode<TObject>::DEF_PARAM(L"values");

// static instantiations: debug level
//
template <class TObject>
Integral::DEBUG TreeNode<TObject>::debug_level_d = Integral::NONE;

// static instantiations: the memory manager
//
template <class TObject>
MemoryManager TreeNode<TObject>::mgr_d(sizeof(TreeNode<TObject>), CLASS_NAME);

// below are all the methods for the TreeNode template class
//      

// ---------------------------------------------------------------------
//
// required static methods
//
//----------------------------------------------------------------------

// method: name
//
// arguments: none
//
// return: a static String& containing the class name
//
// this method returns the class name
//
template<class TObject>
const String& TreeNode<TObject>::name() {
  
  // create the static name string for this class and return it
  //
  static String cname(CLASS_NAME);
  cname.clear();
  cname.concat(CLASS_NAME);
  cname.concat(L"<");
  cname.concat(TObject::name());
  cname.concat(L">");
  
  // return the name
  //
  return cname;
}

// ---------------------------------------------------------------------
//
// required debug methods
//
//----------------------------------------------------------------------

// method: debug
//
// arguments:
//  unichar* msg: (input) information msg
//
// return: a boolean value indicating status
//
// this method dumps the contents of an object to the console
// 
template<class TObject>
boolean TreeNode<TObject>::debug(const unichar* msg_a) const {

  // declare temporary strings to hold class data
  //
  String output;
  String value;

  // dump the item
  //
  value.assign((long)item_d);
  output.debugStr(name(), msg_a, L"item_d", value);
  Console::put(output);
  
  // dump the parent node
  //
  value.assign((long)parent_d);
  output.debugStr(name(), msg_a, L"parent_d", value);
  Console::put(output);  
  
  // dump the left child
  //
  value.assign((long)left_d);
  output.debugStr(name(), msg_a, L"left_d", value);
  Console::put(output);

  // dump the right sibling
  //
  value.assign((long)right_d);
  output.debugStr(name(), msg_a, L"right_d", value);
  Console::put(output);
  
  // exit gracefully
  // 
  return true;
}

//------------------------------------------------------------------------
//
// required destructor/constructor(s)
//
//-----------------------------------------------------------------------

// method: destructor
//
// arguments: none
//
// return: none
//
template<class TObject>
TreeNode<TObject>::~TreeNode() {

  // free memory
  //
  clear();
}

// method: default constructor
//
// arguments: none
//
// return: none
//
template<class TObject>
TreeNode<TObject>::TreeNode(TObject* item_a) {

  // initialize the item
  //
  Node<TObject>::setItem(item_a);
  
  // initialize the remaining member data
  //
  parent_d = (TreeNode<TObject>*)NULL;
  left_d = (TreeNode<TObject>*)NULL;
  right_d = (TreeNode<TObject>*)NULL;
  degree_d = DEF_DEGREE;    
}

// method: copy constructor
//
// arguments:
//  const TreeNode<TObject>& copy_tnode: (input) the TreeNode to copy
//
// return: none
//
template<class TObject>
TreeNode<TObject>::TreeNode(const TreeNode<TObject>& copy_tnode_a) {

  // call the assign method to copy the TreeNode
  //
  assign(copy_tnode_a);
}

//------------------------------------------------------------------------
//
// required assign methods
//
//-------------------------------------------------------------------------

// method: assign
//
// arguments:
//  const TreeNode<TObject>& copy_tnode: (input) the TreeNode to copy
//
// return: a boolean value indicating status
//
// this method copies the contents of the input to this TreeNode
//
template<class TObject>
boolean TreeNode<TObject>::assign(const TreeNode<TObject>& copy_tnode_a) {

  // set the item
  //
  Node<TObject>::assign(copy_tnode_a);
  
  // exit gracefully
  //
  return true;
}

//------------------------------------------------------------------------
//
// required equality methods
//
//------------------------------------------------------------------------

// method: eq
//
// arguments:
//  const TreeNode<TObject>& compare_tnode: (input) the TreeNode to compare
//
// return: a boolean value indicating status
//
// this method compares two TreeNodes for equivalence. two
// TreeNodes are equivalent if all corresponding items are equivalent
//
template<class TObject>
boolean TreeNode<TObject>::eq(const TreeNode<TObject>& compare_tnode_a) const {
 
  // compare the item
  //
  if ((item_d == (TObject*)NULL) ^
      (compare_tnode_a.item_d == (TObject*)NULL)) {
    return false;    
  }

  if ((item_d != (TObject*)NULL) &&
      (compare_tnode_a.item_d != (TObject*)NULL)) {
    if (!Node<TObject>::eq(compare_tnode_a)) {
      return false;
    }
  }
  
  // if we have reached this far then they must be the same
  //
  return true;
}

//-------------------------------------------------------------------------
//
// required memory management methods
//
//-------------------------------------------------------------------------

// method: clear
//
// arguments: 
//    Integral::CMODE cmode_a: (input) clear mode
//  
// return: a boolean value indicating status
//
// this method clears the contents of the list by the setting of cmode_a
//
template<class TObject>
boolean TreeNode<TObject>::clear(Integral::CMODE cmode_a) {

  // clear the item
  //
  if (!Node<TObject>::clear(cmode_a)) {
    return false;
  }
  
  // clear the remaining member data
  //
  if (cmode_a != Integral::RETAIN) {  
    parent_d = (TreeNode<TObject>*)NULL;
    left_d = (TreeNode<TObject>*)NULL;
    right_d = (TreeNode<TObject>*)NULL;
    degree_d = DEF_DEGREE;
  }
  
  // exit gracefully
  //
  return true;
}

//------------------------------------------------------------------------
//
// class-specific public methods:
//  tree node manipulation methods
//
//------------------------------------------------------------------------

// method: setLeftChild
//
// arguments: 
//   const TreeNode* arg: (input) left child 
//  
// return: a boolean value indicating status
//
// this method sets the left child of the current node
//
template<class TObject>
boolean TreeNode<TObject>::setLeftChild(const TreeNode<TObject>* arg_a) {

  // set the left child
  //
  left_d = const_cast<TreeNode<TObject>* >(arg_a);

  // exit gracefully
  //
  return true;
}

// method: setRightSibling
//
// arguments: 
//   const TreeNode* arg: (input) left child 
//  
// return: a boolean value indicating status
//
// this method sets the right sibling of the current node
//
template<class TObject>
boolean TreeNode<TObject>::setRightSibling(const TreeNode<TObject>* arg_a) {

  // set the right sibling
  //
  right_d = const_cast<TreeNode<TObject>* >(arg_a);
  
  // exit gracefully
  //
  return true;
}

// method: isAdjacent
//
// arguments: 
//   const TObject* : (input) object to look for
//  
// return: a boolean value indicating status
//
// this method determines if the object is adjacent to the current node
//
template<class TObject>
boolean TreeNode<TObject>::isAdjacent(const TObject* obj_a) const {

  // verify the input
  //
  if (obj_a == (TObject*)NULL) {
    return Error::handle(name(), L"isAdjacent", Error::ARG, __FILE__, __LINE__);
  }
  
  // check the left child
  //
  if (left_d != (TreeNode<TObject>*)NULL) {
    if (left_d->getItem()->eq(*obj_a)) {
      return true;
    }

    // check the right siblings
    //
    TreeNode<TObject>* rnode = left_d->getRightSibling();
    while (rnode != (TreeNode<TObject>*)NULL) {
      if (rnode->getItem()->eq(*obj_a)) {
	return true;
      }
      rnode = rnode->getRightSibling();
    }
  }

  // if we reach this far then the object must not be adjacent
  //
  return false;
}

// method: isAdjacent
//
// arguments: 
//   const TObject* : (input) object to look for
//  
// return: a boolean value indicating status
//
// this method determines if the object is adjacent to the current node
//
template<class TObject>
boolean TreeNode<TObject>::isAdjacent(const TreeNode<TObject>* node_a) const {

  // verify the input
  //
  if (node_a == (TreeNode<TObject>*)NULL) {
    return Error::handle(name(), L"isAdjacent", Error::ARG, __FILE__, __LINE__);
  }
  
  // check the left child
  //
  if (left_d != (TreeNode<TObject>*)NULL) {
    if (left_d->eq(*node_a)) {
      return true;
    }

    // check the right siblings
    //
    TreeNode<TObject>* rnode = left_d->getRightSibling();
    while (rnode != (TreeNode<TObject>*)NULL) {
      if (rnode->eq(*node_a)) {
	return true;
      }
      rnode = rnode->getRightSibling();
    }
  }

  // if we reach this far then the object must not be adjacent
  //
  return false;
}

// end of include file
//
#endif
