// file: $isip/class/dstr/PriorityQueue/PriorityQueueDiagnose.h
// version: $Id: PriorityQueueDiagnose.h 10636 2007-01-26 22:18:09Z tm334 $
//

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

// isip include files
//
#ifndef ISIP_PRIORITY_QUEUE
#include <PriorityQueue.h>
#endif

// PriorityQueueDiagnose: a class that contains the diagnose method of PriorityQueue class.
//
template<class TObject>
class PriorityQueueDiagnose : public PriorityQueue<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 PriorityQueue<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 PriorityQueueDiagnose 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 PriorityQueueDiagnose<TObject>::diagnose(Integral::DEBUG level_a) {

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

  // output the class name
  //
  if (level_a > Integral::NONE) {
    SysString output(L"diagnosing class ");
    output.concat(PriorityQueue<TObject>::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 construction methods
  //
  Long lng_00(3);
  PriorityQueue<Long> pq_0; 
  PriorityQueue<Long> pq_1; 
    
  // test the assign and equality method
  //
  if (!pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }
  
  pq_0.assign(pq_1);
  if (!pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }  

  pq_0.push(&lng_00);
  if (pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }

  pq_1.assign(pq_0);
  if (!pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }

  pq_0.pop(&lng_00);
  if (pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }

  pq_1.pop(&lng_00);
  if (!pq_0.eq(pq_1)) {
    return Error::handle(name(), L"eq", Error::TEST, __FILE__, __LINE__);
  }  
    
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------------
  //
  // 2. priority queue property methods
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing priority queue property methods...\n");
    Console::increaseIndention();
  }

  PriorityQueue<Long> pq_2; 
  PriorityQueue<Long> pq_3;

  // test the length methods
  //
  if (!pq_2.setLength(10)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  if (pq_2.length() != 10) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  if (!pq_3.setLength(5)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  if (pq_3.length() != 5) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }  

  // test the capacity methods
  //  
  if (!pq_2.setCapacity(10)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  if (pq_2.getCapacity() != 10) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  if (!pq_3.setCapacity(5)) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }
  if (pq_3.getCapacity() != 5) {
    return Error::handle(name(), L"diagnose", Error::TEST, __FILE__, __LINE__);
  }

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------------
  //
  // 4. priority queue push, pop and top methods
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing priority queue push, pop and top methods...\n");
    Console::increaseIndention();
  }  

  PriorityQueue<Long> pq_00;

  // create some test data
  //
  Long vec_00[1000];
  for (long i=0; i < 1000; i++) {
    vec_00[i].assign((long)i);
  }

  // test the push/top method SYSTEM mode
  //
  for (long i=0; i < 1000; i++) {
    if (!pq_00.push(&vec_00[i])) {
      return Error::handle(name(), L"push", Error::TEST, __FILE__, __LINE__);
    }
    if (!pq_00.top()->eq(vec_00[i])) {
      return Error::handle(name(), L"push", Error::TEST, __FILE__, __LINE__);
    }
  }

  // test the pop/top methods SYSTEM mode
  //
  for (long i=0; i < 1000; i++) {
    if (!pq_00.top()->eq(vec_00[1000 - i - 1])) {
      return Error::handle(name(), L"top", Error::TEST, __FILE__, __LINE__);
    }

    Long val;    
    pq_00.pop(&val);
    if (!val.eq(vec_00[1000 - i - 1])) {
      return Error::handle(name(), L"pop", Error::TEST, __FILE__, __LINE__);
    }
  }

  // free memory
  //
  pq_00.clear();
  
  PriorityQueue<Long> pq_01(DstrBase::USER);
  
  // create some test data
  //
  Long* vec_01[1000];
  for (long i=0; i < 1000; i++) {
    vec_01[i] = new Long((long)i);
  }

  // test the push/top method USER mode
  //
  for (long i=0; i < 1000; i++) {
    if (!pq_01.push(vec_01[i])) {
      return Error::handle(name(), L"push", Error::TEST, __FILE__, __LINE__);
    }
    if (pq_01.top() != vec_01[i]) {
      return Error::handle(name(), L"push", Error::TEST, __FILE__, __LINE__);
    }
  }

  // test the pop/top methods USER mode
  //
  for (long i=0; i < 1000; i++) {
    if (pq_01.top() != vec_01[1000 - i - 1]) {
      return Error::handle(name(), L"top", Error::TEST, __FILE__, __LINE__);
    }

    if (pq_01.pop() != vec_01[1000 - i - 1]) {
      return Error::handle(name(), L"pop", Error::TEST, __FILE__, __LINE__);
    }
  }

  // free memory
  //
  pq_01.clear();
  for (long i=0; i < 1000; i++) {
    delete vec_01[i];
  }
  
  // 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
