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

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

// isip include files
//
#ifndef ISIP_TREE_NODE
#include <TreeNode.h>
#endif

#ifndef ISIP_ULONG
#include <Ulong.h>
#endif

// TreeNodeDiagnose: a class that contains the diagnose method of TreeNode class.
//
template<class TObject>
class TreeNodeDiagnose : public TreeNode<TObject> {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------

  // default values
  //
    
  // default arguments to methods
  //
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const String& name() {
    return TreeNode<TObject>::name();
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);

  // debug methods
  //  these methods are omitted since this class does not have data
  //  members and operations  
  //
  
  // destructor/constructor(s):
  //  these methods are omitted since this class does not have data
  //  members and operations
  //

  // assign methods:
  //  these methods are omitted since this class does not have data
  //  members and operations
  //

  // operator= methods:
  //  these methods are omitted since this class does not have data
  //  members and operations
  //  

  // i/o methods:
  //  these methods are omitted since this class does not have data
  //  members and operations
  //

  // equality methods:
  //  these methods are omitted since this class does not have data
  //  members and operations
  //

  // memory-management methods:
  //  these methods are omitted since this class does not have data
  //  members and operations
  //
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  //  these methods are omitted since this class does not have data
  //  members and operations
  //
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

}; 

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

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

// method: diagnose
//
// arguments:
//  Integral::DEBUG level: (input) debug level for diagnostics
//
// return: a boolean value indicating status
//
template<class TObject>
boolean TreeNodeDiagnose<TObject>::diagnose(Integral::DEBUG level_a) {

  //---------------------------------------------------------------------------
  //
  // 0. preliminaries
  //
  //---------------------------------------------------------------------------

  // output the class name
  //
  if (level_a > Integral::NONE) {
    SysString output(L"diagnosing class ");
    output.concat(CLASS_NAME);
    output.concat(L": ");
    Console::put(output);
    Console::increaseIndention();
  }

  //---------------------------------------------------------------------
  //
  // 1. required public methods
  //
  //---------------------------------------------------------------------
  
  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods...\n");
    Console::increaseIndention();
  }
  
  // test the constructors
  //
  Ulong* val = new Ulong();
  
  TreeNode<Ulong> tnode_00(val);  
  TreeNode<Ulong> tnode_01(tnode_00);

  if (!tnode_00.eq(tnode_01)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // large scale testing
  //
  TreeNode<Ulong>** vec_00 = (TreeNode<Ulong>**)NULL;
  vec_00 = new TreeNode<Ulong>*[1000];

  TreeNode<Ulong>** vec_01 = (TreeNode<Ulong>**)NULL;
  vec_01 = new TreeNode<Ulong>*[1000];  
  
  for (int i=0; i < 1000; i++) {
    vec_00[i] = new TreeNode<Ulong>(val);
    vec_01[i] = new TreeNode<Ulong>(*vec_00[i]);    
  }

  for (int i=0; i < 1000; i++) {
    if (!vec_00[i]->eq(*(vec_01[i]))) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
  }

  delete val;  
  for (int i=0; i < 1000; i++) {
    delete vec_00[i];
    delete vec_01[i];    
  }
  delete [] vec_00;
  delete [] vec_01;
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //---------------------------------------------------------------------
  //
  // 2. tree node manipulation methods
  //
  //---------------------------------------------------------------------
  
  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing tree node manipulation methods...\n");
    Console::increaseIndention();
  }

  // test the degree method
  //  
  TreeNode<Ulong> tnode_02;

  // degree must be zero
  //
  if (tnode_02.degree() != 0) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tnode_02.increment();
  
  // degree must be one
  //
  if (tnode_02.degree() != 1) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tnode_02.increment();
  tnode_02.increment();
  tnode_02.increment();  
  
  // degree must be one
  //
  if (tnode_02.degree() != 4) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tnode_02.decrement();
  tnode_02.decrement();  
  
  // degree must be one
  //
  if (tnode_02.degree() != 2) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }      

  // test the parent methods
  //  
  TreeNode<Ulong>* tnode_03 = new TreeNode<Ulong>();
  TreeNode<Ulong>* tnode_04 = new TreeNode<Ulong>();

  // parent must be null
  //
  if (tnode_02.getParent() != (TreeNode<Ulong>*)NULL) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tnode_02.setParent(tnode_03);
  
  // parent must be tnode_03
  //
  if (tnode_02.getParent() != tnode_03) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tnode_02.setParent(tnode_04);
  
  // parent must be tnode_04
  //
  if (tnode_02.getParent() != tnode_04) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }    

  // test the left child/right sibling methods
  //
  Ulong* val_05 = new Ulong(5);
  
  TreeNode<Ulong>* tnode_05 = new TreeNode<Ulong>(val_05);
  TreeNode<Ulong>* tnode_06 = new TreeNode<Ulong>();

  // left child must be null
  //
  if (tnode_02.getLeftChild() != (TreeNode<Ulong>*)NULL) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  
  tnode_02.setLeftChild(tnode_05);

  // left child must be tnode_05
  //
  if (tnode_02.getLeftChild() != tnode_05) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  if (!tnode_02.isAdjacent(val_05)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  if (!tnode_02.isAdjacent(tnode_05)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  
  // right sibling must be null
  //
  if (tnode_02.getRightSibling() != (TreeNode<Ulong>*)NULL) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  
  tnode_02.setRightSibling(tnode_06);

  // left child must be tnode_06
  //
  if (tnode_02.getRightSibling() != tnode_06) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  
  // clean up memory
  //
  delete val_05;
  
  delete tnode_03;
  delete tnode_04;
  delete tnode_05;
  delete tnode_06;
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //---------------------------------------------------------------------------
  //
  // 8. print completion message
  //
  //---------------------------------------------------------------------------
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  // possibly print completion message
  //
  if (level_a > Integral::NONE) {
    String output(L"diagnostics completed successfully for class ");
    output.concat(name());
    output.concat(L"\n");
    Console::put(output);
  }
  
  // exit gracefully
  //
  return true;
}

// end of include file
//
#endif
