// file: $isip/class/dstr/Tree/TreeDiagnose.h
// version: $Id: TreeDiagnose.h 8653 2002-08-26 18:37:37Z alphonso $
//

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

// isip include files
//
#ifndef ISIP_TREE
#include <Tree.h>
#endif

// TreeDiagnose: a class that contains the diagnose method of Tree class.
//
template<class TObject>
class TreeDiagnose : public Tree<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 Tree<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 TreeDiagnose 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 TreeDiagnose<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();
  }

  // create an example tree
  //
  // ROOT -> 'a'
  //      -> 'b' -> 'd'
  //      -> 'c' -> 'e'
  //             -> 'f'
  //
  Char* char_a = new Char('a');
  Char* char_b = new Char('b');
  Char* char_c = new Char('c');
  Char* char_d = new Char('d');
  Char* char_e = new Char('e');
  Char* char_f = new Char('f');      

  // test the default constructors
  //
  Tree<Char> tree_00;
  TreeNode<Char>* node_b = (TreeNode<Char>*)NULL;
  TreeNode<Char>* node_c = (TreeNode<Char>*)NULL;

  // test the insert and insert child methods
  //
  tree_00.insertChild(tree_00.getRoot(), tree_00.insert(char_a));
  node_b = tree_00.insert(char_b);
  tree_00.insertChild(tree_00.getRoot(), node_b);
  node_c = tree_00.insert(char_c);
  tree_00.insertChild(tree_00.getRoot(), node_c);

  tree_00.insertChild(node_b, tree_00.insert(char_d));

  tree_00.insertChild(node_c, tree_00.insert(char_e));
  tree_00.insertChild(node_c, tree_00.insert(char_f));      

  // test the copy constructor
  //
  Tree<Char> tree_01(tree_00);

  // the two tree structures must be equal
  //
  if (!tree_00.eq(tree_01)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // test the get method
  //  
  Vector<Ulong> root_adj_00;
  SingleLinkedList<Char> node_obj_00;
  SingleLinkedList<Vector<Ulong> > node_adj_00;

  tree_00.get(root_adj_00, node_obj_00, node_adj_00);
  
  // test the set method
  //
  Tree<Char> tree_02;
  
  Vector<Ulong> root_adj_01;
  SingleLinkedList<Char> node_obj_01;
  SingleLinkedList<Vector<Ulong> > node_adj_01;
  
  tree_02.set(root_adj_00, node_obj_00, node_adj_00);

  // the two tree structures must be equal
  //
  if (!tree_00.eq(tree_02)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  
  // free allocated memory
  //
  delete char_a;
  delete char_b;
  delete char_c;
  delete char_d;
  delete char_e;
  delete char_f;    

  {
    
    // create an example tree
    //
    // ROOT -> 'a'
    //      -> 'b' -> 'd'
    //      -> 'c' -> 'e'
    //             -> 'f'
    //
    Char* char_a = new Char('a');
    Char* char_b = new Char('b');
    Char* char_c = new Char('c');
    Char* char_d = new Char('d');
    Char* char_e = new Char('e');
    Char* char_f = new Char('f');      
    
    // test the default constructors
    //
    Tree<Char> tree_00(DstrBase::USER);
    TreeNode<Char>* node_b = (TreeNode<Char>*)NULL;
    TreeNode<Char>* node_c = (TreeNode<Char>*)NULL;
    
    // test the insert and insert child methods
    //
    tree_00.insertChild(tree_00.getRoot(), tree_00.insert(char_a));
    node_b = tree_00.insert(char_b);
    tree_00.insertChild(tree_00.getRoot(), node_b);
    node_c = tree_00.insert(char_c);
    tree_00.insertChild(tree_00.getRoot(), node_c);
    
    tree_00.insertChild(node_b, tree_00.insert(char_d));
    
    tree_00.insertChild(node_c, tree_00.insert(char_e));
    tree_00.insertChild(node_c, tree_00.insert(char_f));      
    
    // test the copy constructor
    //
    Tree<Char> tree_01(tree_00);
    
    // the two tree structures must be equal
    //
    if (!tree_00.eq(tree_01)) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
    
    // test the get method
    //  
    Vector<Ulong> root_adj_00;
    SingleLinkedList<Char> node_obj_00;
    SingleLinkedList<Vector<Ulong> > node_adj_00;
    
    tree_00.get(root_adj_00, node_obj_00, node_adj_00);
    
    // test the set method
    //
    Tree<Char> tree_02(DstrBase::USER);
    
    Vector<Ulong> root_adj_01;
    SingleLinkedList<Char> node_obj_01;
    SingleLinkedList<Vector<Ulong> > node_adj_01;
    
    tree_02.set(root_adj_00, node_obj_00, node_adj_00);
    
    // the two tree structures must be equal
    //
    if (!tree_00.eq(tree_02)) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }

    // free allocated memory
    //
    delete char_a;
    delete char_b;
    delete char_c;
    delete char_d;
    delete char_e;
    delete char_f;    
  }
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

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

  // create an example tree
  //
  // ROOT -> '0'
  //      -> '1' -> '3' -> '8'
  //                    -> '9'
  //             -> '4'
  //             -> '5' -> '10'
  //      -> '2' -> '6'
  //             -> '7' -> '11'
  //                    -> '12'
  //
  Ulong* ulong_0 = new Ulong(0);
  Ulong* ulong_1 = new Ulong(1);
  Ulong* ulong_2 = new Ulong(2);
  Ulong* ulong_3 = new Ulong(3);
  Ulong* ulong_4 = new Ulong(4);
  Ulong* ulong_5 = new Ulong(5);
  Ulong* ulong_6 = new Ulong(6);
  Ulong* ulong_7 = new Ulong(7);
  Ulong* ulong_8 = new Ulong(8);  
  Ulong* ulong_9 = new Ulong(9);
  Ulong* ulong_10 = new Ulong(10);
  Ulong* ulong_11 = new Ulong(11);
  Ulong* ulong_12 = new Ulong(12);

  Tree<Ulong> tree_03;  
  TreeNode<Ulong>* node_1 = (TreeNode<Ulong>*)NULL;
  TreeNode<Ulong>* node_2 = (TreeNode<Ulong>*)NULL;
  TreeNode<Ulong>* node_3 = (TreeNode<Ulong>*)NULL;
  TreeNode<Ulong>* node_5 = (TreeNode<Ulong>*)NULL;
  TreeNode<Ulong>* node_7 = (TreeNode<Ulong>*)NULL;      

  // ROOT -> 0
  tree_03.insertChild(tree_03.getRoot(), tree_03.insert(ulong_0));

  // ROOT -> 1
  node_1 = tree_03.insert(ulong_1);
  tree_03.insertChild(tree_03.getRoot(), node_1);

  // 1 -> 3
  node_3 = tree_03.insert(ulong_3);
  tree_03.insertChild(node_1, node_3);

  // 3 -> 8
  tree_03.insertChild(node_3, tree_03.insert(ulong_8));

  // 3 -> 9  
  tree_03.insertChild(node_3, tree_03.insert(ulong_9));  

  // 1 -> 4  
  tree_03.insertChild(node_1, tree_03.insert(ulong_4));  

  // 1 -> 5  
  node_5 = tree_03.insert(ulong_5);
  tree_03.insertChild(node_1, node_5);  

  // 5 -> 10    
  tree_03.insertChild(node_5, tree_03.insert(ulong_10));

  // ROOT -> 2
  node_2 = tree_03.insert(ulong_2);
  tree_03.insertChild(tree_03.getRoot(), node_2);  

  // 2 -> 6
  tree_03.insertChild(node_2, tree_03.insert(ulong_6));

  // 2 -> 7
  node_7 = tree_03.insert(ulong_7);
  tree_03.insertChild(node_2, node_7);

  // 7 -> 11
  tree_03.insertChild(node_7, tree_03.insert(ulong_11));

  // 7 -> 12
  tree_03.insertChild(node_7, tree_03.insert(ulong_12));  

  Tree<Ulong> tree_04;  
  node_1 = (TreeNode<Ulong>*)NULL;
  node_2 = (TreeNode<Ulong>*)NULL;
  node_3 = (TreeNode<Ulong>*)NULL;
  node_5 = (TreeNode<Ulong>*)NULL;
  node_7 = (TreeNode<Ulong>*)NULL;

  // ROOT -> 0
  tree_04.insertChild(tree_04.getRoot(), tree_04.insert(ulong_0));

  // ROOT -> 1
  node_1 = tree_04.insert(ulong_1);
  tree_04.insertChild(tree_04.getRoot(), node_1);

  // 1 -> 3
  node_3 = tree_04.insert(ulong_3);
  tree_04.insertChild(node_1, node_3);

  // 3 -> 8
  tree_04.insertChild(node_3, tree_04.insert(ulong_8));

  // 3 -> 9  
  tree_04.insertChild(node_3, tree_04.insert(ulong_9));  

  // 1 -> 4  
  tree_04.insertChild(node_1, tree_04.insert(ulong_4));  

  // 1 -> 5  
  node_5 = tree_04.insert(ulong_5);
  tree_04.insertChild(node_1, node_5);  

  // 5 -> 10    
  tree_04.insertChild(node_5, tree_04.insert(ulong_10));

  // ROOT -> 2
  node_2 = tree_04.insert(ulong_2);
  tree_04.insertChild(tree_04.getRoot(), node_2);  

  // 2 -> 6
  tree_04.insertChild(node_2, tree_04.insert(ulong_6));

  // 2 -> 7
  node_7 = tree_04.insert(ulong_7);
  tree_04.insertChild(node_2, node_7);

  // 7 -> 11
  tree_04.insertChild(node_7, tree_04.insert(ulong_11));

  // 7 -> 12
  tree_04.insertChild(node_7, tree_04.insert(ulong_12));  

  // tree_03 and tree_04 must be equal
  //
  if (!tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // find the '12' in tree_03
  //
  if (!tree_03.contains(ulong_12)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_03.find(ulong_12)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tree_03.remove();

  // tree_03 and tree_04 must not be equal
  //
  if (tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // find the '12' in tree_04
  //
  if (!tree_04.contains(ulong_12)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_04.find(ulong_12)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  Ulong* val = new Ulong();
  tree_04.remove(val);

  // tree_03 and tree_04 must be equal
  //
  if (!tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!val->eq(*ulong_12)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  delete val;

  // find the '7' in tree_03
  //
  if (!tree_03.contains(ulong_7)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_03.find(ulong_7)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tree_03.remove();
  
  // tree_03 and tree_04 must not be equal
  //
  if (tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // find the '7' in tree_04
  //
  if (!tree_04.contains(ulong_7)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_04.find(ulong_7)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  val = new Ulong();
  tree_04.remove(val);

  // tree_03 and tree_04 must be equal
  //
  if (!tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!val->eq(*ulong_7)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  delete val;  

  // find the '2' in tree_03
  //
  if (!tree_03.contains(ulong_2)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_03.find(ulong_2)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  tree_03.remove();
  
  // tree_03 and tree_04 must not be equal
  //
  if (tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // find the '2' in tree_04
  //
  if (!tree_04.contains(ulong_2)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!tree_04.find(ulong_2)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  val = new Ulong();
  tree_04.remove(val);

  // tree_03 and tree_04 must be equal
  //
  if (!tree_03.eq(tree_04)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  
  if (!val->eq(*ulong_2)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  delete val;  

  // free allocated memory
  //
  delete ulong_0;
  delete ulong_1;
  delete ulong_2;
  delete ulong_3;
  delete ulong_4;
  delete ulong_5;
  delete ulong_6;
  delete ulong_7;
  delete ulong_8;
  delete ulong_9;
  delete ulong_10;    
  delete ulong_11;
  delete ulong_12;

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


  // create an example tree
  //
  // '7' -> '3' -> '1'
  //            -> '2'
  //     -> '6' -> '4'
  //            -> '5'
  //
  Char* char_7 = new Char('7');
  Char* char_6 = new Char('6');
  Char* char_5 = new Char('5');
  Char* char_4 = new Char('4');
  Char* char_3 = new Char('3');
  Char* char_2 = new Char('2');
  Char* char_1 = new Char('1');        

  // test the default constructors
  //
  Tree<Char> tree_05;

  TreeNode<Char>* node_03 = (TreeNode<Char>*)NULL;
  TreeNode<Char>* node_06 = (TreeNode<Char>*)NULL;

  // 7
  tree_05.setRootItem(char_7);

  // 7 -> 3
  node_03 = tree_05.insert(char_3);
  tree_05.insertChild(tree_05.getRoot(), node_03);

  // 3 -> 1
  tree_05.insertChild(node_03, tree_05.insert(char_1));  
  
  // 3 -> 2
  tree_05.insertChild(node_03, tree_05.insert(char_2));  
  
  // 7 -> 6
  node_06 = tree_05.insert(char_6);
  tree_05.insertChild(tree_05.getRoot(), node_06);  

  // 6 -> 4
  tree_05.insertChild(node_06, tree_05.insert(char_4));
  tree_05.insertChild(node_06, tree_05.insert(char_5));

  SingleLinkedList<TreeNode<TObject> > list_00(DstrBase::USER);
  SingleLinkedList<TObject> result_00(DstrBase::USER);

  result_00.insert(char_1);
  result_00.insert(char_2);
  result_00.insert(char_3);
  result_00.insert(char_4);
  result_00.insert(char_5);
  result_00.insert(char_6);
  result_00.insert(char_7);  
  
  tree_05.postorderTreeTraversal(list_00);

  list_00.gotoFirst();
  for (boolean more = result_00.gotoFirst(); more;
       more = result_00.gotoNext()) {
    if (!result_00.getCurr()->eq(*list_00.getCurr()->getItem())) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
    list_00.gotoNext();
  }
  
  SingleLinkedList<TreeNode<TObject> > list_01(DstrBase::USER);
  SingleLinkedList<TObject> result_01(DstrBase::USER);

  result_01.insert(char_7);
  result_01.insert(char_3);
  result_01.insert(char_1);
  result_01.insert(char_2);
  result_01.insert(char_6);
  result_01.insert(char_4);
  result_01.insert(char_5);
  
  tree_05.preorderTreeTraversal(list_01);

  list_01.gotoFirst();
  for (boolean more = result_01.gotoFirst(); more;
       more = result_01.gotoNext()) {
    if (!result_01.getCurr()->eq(*list_01.getCurr()->getItem())) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
    list_01.gotoNext();
  }
  
  SingleLinkedList<TreeNode<TObject> > list_02(DstrBase::USER);
  SingleLinkedList<TObject> result_02(DstrBase::USER);

  result_02.insert(char_1);
  result_02.insert(char_3);
  result_02.insert(char_2);
  result_02.insert(char_7);
  result_02.insert(char_4);
  result_02.insert(char_6);
  result_02.insert(char_5);
  
  tree_05.inorderTreeTraversal(list_02);

  list_02.gotoFirst();
  for (boolean more = result_02.gotoFirst(); more;
       more = result_02.gotoNext()) {
    if (!result_02.getCurr()->eq(*list_02.getCurr()->getItem())) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
    list_02.gotoNext();
  }
  
  SingleLinkedList<TreeNode<TObject> > list_03(DstrBase::USER);
  SingleLinkedList<TObject> result_03(DstrBase::USER);

  result_03.insert(char_7);
  result_03.insert(char_3);
  result_03.insert(char_6);
  result_03.insert(char_1);
  result_03.insert(char_2);
  result_03.insert(char_4);
  result_03.insert(char_5);
  
  tree_05.levelorderTreeTraversal(list_03);      

  list_03.gotoFirst();
  for (boolean more = result_03.gotoFirst(); more;
       more = result_03.gotoNext()) {
    if (!result_03.getCurr()->eq(*list_03.getCurr()->getItem())) {
      return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
    }
    list_03.gotoNext();
  }
  
  // free allocated memory
  //
  delete char_1;
  delete char_2;
  delete char_3;
  delete char_4;
  delete char_5;
  delete char_6;
  delete char_7;
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //---------------------------------------------------------------------------
  //
  // 3. 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
