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

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

// isip include files
//
#ifndef ISIP_DSTR_BASE
#include <DstrBase.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_CHAR
#include <Char.h>
#endif

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

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

// PriorityQueue: this class implements a standard priority queue
// using a vector to implement the underlying heap data structure.
//
template<class TObject>
class PriorityQueue : public DstrBase {
  
  //---------------------------------------------------------------------------
  //
  // 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_END_POS = -1;
  
  // default arguments to methods
  //
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // comparison function for the items in the priority queue
  //
  typedef Integral::COMPARE (*COMPARE_FUNC)(TObject* item1, TObject* item2);
  
  // the internal structure of the priority queue
  //
  TObject** v_d;

  // the allocation mode
  //
  ALLOCATION alloc_d;

  // number of elements of this vector
  //
  Long length_d;

  // the maximum number of elements
  //
  Long capacity_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 PriorityQueueDiagnose.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* message) const;
     
  // destructor/constructor(s)
  //
  ~PriorityQueue();
  PriorityQueue(ALLOCATION alloc = DEF_ALLOCATION);
  PriorityQueue(const PriorityQueue<TObject>& copy_queue);

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

  // method: eq
  //
  boolean eq(const PriorityQueue<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(this->name(), L"read", Error::ARG, __FILE__, __LINE__);
  }

  // method: write
  //  
  boolean write(Sof& sof, long tag, const String& name) const {
    return Error::handle(this->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);
  }
    
  // method: clear
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  priority queue push, pop and top methods
  //
  //---------------------------------------------------------------------------

  // method inserts an intem into the priority queue
  //
  boolean push(TObject* item, COMPARE_FUNC comp_func = compare);

  // method removes the largest item from the priority queue
  //
  TObject* pop(TObject* item = (TObject*)NULL);  

  // method: top
  //
  const TObject* top() const;
  TObject* top();  

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  size-related methods
  //
  //--------------------------------------------------------------------------

  // method: isEmpty
  //
  boolean isEmpty() const {
    return ((long)length_d == 0);
  }

  // method: length
  //
  long length() const {
    return (long)length_d;
  }

  // method: getCapacity
  //
  long getCapacity() const {
    return (long)capacity_d;
  }
  
  // resize methods
  //
  boolean setLength(long length, boolean preserve_values = true);
  boolean setCapacity(long capacity, boolean preserve_values = true);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------

private:


  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  priority queue property methods
  //
  //---------------------------------------------------------------------------
  
  // method: parent
  //
  long parent(long val) {
    return (val - 1) / 2;
  }

  // method: left
  //
  long left(long val) {
    return  (2 * val) + 1;
  }

  // method: right
  //
  long right(long val) {
    return (2 * val) + 2;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  heap manipulation methods
  //
  //-------------------------------------------------------------------------- 

  // this method evaluates the kernel for the input vectors
  //
  static Integral::COMPARE compare(TObject* item1, TObject* item2);
  
  // method to reorder the heap and maintain the heap property
  //
  boolean heapify(long index, COMPARE_FUNC comp_func = compare);

  // method to construct a heap out of an existing array
  //
  boolean buildHeap();

  // method to sort an existing heap
  //
  boolean heapSort();

  // method to access the heap based on the mode
  //
  TObject* accessByMode(TObject* item);
};

//-----------------------------------------------------------------------------
//
// 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 PriorityQueue<TObject>::CLASS_NAME(L"PriorityQueue");

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

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

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

// below are all the methods for the Queue 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& PriorityQueue<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* message: (input) information message
//
// return: a boolean value indicating status
//
// this method dumps the contents of an object to the console
// 
template<class TObject>
boolean PriorityQueue<TObject>::debug(const unichar* message_a) const {

  // declare temporary strings to hold class data
  //
  String output;
  String value;
  String param;
  String numeric;
  
  // dump the length
  //
  value.assign((long)length_d);
  output.debugStr(name(), message_a, L"length_d", value);
  Console::put(output);

  // dump the capacity
  //
  value.assign((long)capacity_d);
  output.debugStr(name(), message_a, L"capacity_d", value);
  Console::put(output);

  // dump the values
  //
  for (long i = 0; i < (long)length_d; i++) {

    param.assign(L"v_d[");
    value.assign(i);

    param.concat(value);
    param.concat(L"]");
    output.debugStr(name(), message_a, param);
    Console::put(output);

    // increase indention
    //
    Console::increaseIndention();
    
    // call the debug method of the element
    //
    if (v_d[i] != (TObject*)NULL) {
      v_d[i]->debug(L"");
    }

    Console::decreaseIndention();
  }
  
  // exit gracefully
  // 
  return true;
}

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

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

  // free memory
  //
  clear(Integral::RELEASE);
}

// method: default constructor
//
// arguments:
//  ALLOCATION alloc: (input) the flag to specify whether or not the item
//                     memory is allocated by the node itself
//
// return: none
//
template<class TObject>
PriorityQueue<TObject>::PriorityQueue(ALLOCATION alloc_a) {

  // initialize data
  // 
  length_d = (long)0;
  capacity_d = (long)0;
  v_d = (TObject**)NULL;
  
  // set the allocation flag
  //
  alloc_d = alloc_a;
}

// method: copy constructor
//
// arguments:
//  const PriorityQueue<TObject>& copy_queue: (input) the queue to copy
//
// return: none
//
template<class TObject>
PriorityQueue<TObject>::PriorityQueue(const PriorityQueue<TObject>& copy_queue_a) {

  // initialize data
  // 
  length_d = (long)0;
  capacity_d = (long)0;
  v_d = (TObject**)NULL;
  
  // call the assign method to copy the queue
  //
  assign(copy_queue_a);
}

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

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

  // resize the vector
  // 
  if (!setLength(copy_queue_a.length(), false)) {
    return Error::handle(name(), L"assign", Error::NOMEM, __FILE__, __LINE__);
  }
  
  // copy the data
  // 
  for (long index = 0; index < (long)length_d; index++) {
    v_d[index] = accessByMode(copy_queue_a.v_d[index]);
  }

  // exit gracefully
  //
  return true;
}

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

// method: eq
//
// arguments:
//  const PriorityQueue<TObject>& compare_queue: (input) the queue to compare
//
// return: a boolean value indicating status
//
// this method compares two queues for equivalence. two queues are equivalent
// if all corresponding items are equivalent
//
template<class TObject>
boolean PriorityQueue<TObject>::eq(const PriorityQueue<TObject>& compare_queue_a) const {
  
  // declare the output variable
  //
  boolean are_equal = true;

  // two PriorityQueues can not be equivalent if they are of differing lengths
  //
  if ((long)length_d != (long)compare_queue_a.length_d) {
    
    // set the break flag
    //
    are_equal = false;
  }

  // loop over each element and see if each is equivalent
  //
  for (long i = 0; are_equal && (i < (long)length_d); i++) {
    
    // see if the current items are equal
    //
    if (alloc_d == SYSTEM) {
      if (!v_d[i]->eq(*compare_queue_a.v_d[i])) {
	are_equal = false;
      }
    }
    else {
      if (v_d[i] != compare_queue_a.v_d[i]) {
	are_equal = false;
      }
    }
  }
  
  // return a value representing if they are equivalent
  //
  return are_equal;
}

//-------------------------------------------------------------------------
//
// 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
//
//  enum CMODE { RETAIN = 0, RESET, RELEASE, FREE, DEF_CMODE = RESET };
//
// RETAIN: call clear with RETAIN on each element in the queue
//
// RESET: clear the structure but don't necessarily delete memory
//
// RELEASE: clear the structure and release memory
//
// FREE: clear the structure and release memory
//
// Programming hint:
//
// use the clear() method to manage the memory of the objects going
// into the queue.
// particular useful when queue is in USER mode. Caution the object
// you place into queue must have a clear method that meets the
// requirements of the IFC clear method.
//
//
template<class TObject>
boolean PriorityQueue<TObject>::clear(Integral::CMODE cmode_a) {

  // if the cmode_a is RETAIN or FREE, call clear(cmode_a) method for
  // each element
  //  
  if ((cmode_a == Integral::RETAIN) || (cmode_a == Integral::FREE)) {

    // loop over all elements
    //
    for (long i = 0; i < (long)length_d; i++) {
      v_d[i]->clear(cmode_a);
    }
  }

  // if the cmode_a is RESET, clear the structure but don't 
  // necessarily delete memory
  //    
  if (cmode_a == Integral::RESET) {
    setLength(0);
  }
  
  // if the cmode_a is RELEASE or FREE, clear the structure and
  // release memory.
  //
  else if ((cmode_a == Integral::RELEASE) || (cmode_a == Integral::FREE)) {

    // free memory -- the setCapacity call will actually release it.
    //
    setCapacity(0);
    length_d = 0;
  }
  
  // exit gracefully
  //
  return true;
}

//------------------------------------------------------------------------
//
// class-specific public methods:
//  get and set methods
//
//------------------------------------------------------------------------

// method: setLength
// 
// arguments:
//  long length: (input) new length
//  boolean preserve_values: (input) should we save the memory
//   
// return: a boolean value indicating status
//
// this method sets the length, or number of valid elements
//
template<class TObject>
boolean PriorityQueue<TObject>::setLength(long length_a, boolean preserve_values_a) {

  // check arguments
  // 
  if (length_a < 0) {
    return Error::handle(name(), L"setLength", Error::ARG, __FILE__, __LINE__);
  }
  
  // if new length is greater than capacity, call setCapacity
  //
  if (length_a > capacity_d) {
    if (!setCapacity(length_a, preserve_values_a)) {
      return Error::handle(name(), L"setLength", Error::NOMEM,
			   __FILE__, __LINE__);
    }
  }

  // set new length
  // 
  length_d = length_a;
    
  // exit gracefully
  // 
  return true;
}

// method: setCapacity
// 
// arguments:
//  long capacity: (input) new capacity
//  boolean preserve_values: (input) should we save the memory
//   
// return: a boolean value indicating status
//
// this method sets the capacity, which is the maximum number of elements
// this queue can hold.
//
template<class TObject>
boolean PriorityQueue<TObject>::setCapacity(long capacity_a,
				     boolean preserve_values_a) {
  
  // capacity_a < 0: error
  // 
  if (capacity_a < 0) {
    return Error::handle(name(), L"setCapacity",
			 Error::ARG, __FILE__, __LINE__);
  }

  // capacity_a = capacity_d: done
  //
  else if (capacity_a == capacity_d) {
    return true;
  }

  // capacity_a == 0 (and length_d == 0): just delete memory
  //
  else if (capacity_a == 0) {
    
    // delete the old memory
    //
    if (v_d != (TObject**)NULL) {
      if (alloc_d == SYSTEM) {
	for (long i=0; i < (long)length_d; i++) {
	  if (v_d[i] != (TObject*)NULL) {
	    delete v_d[i];
	    v_d[i] = (TObject*)NULL;
	  }
	}
      }
      delete [] v_d;
      v_d = (TObject**)NULL;
    }
  }
  
  // capacity_a >= length_d: we will need to allocate memory and/or
  // transfer data.
  //
  else {

    // allocate a new chunk of memory
    //
    TObject** new_mem = new TObject*[capacity_a];
    if (new_mem == (TObject**)NULL) {
      return Error::handle(name(), L"setCapacity", Error::NOMEM,
			   __FILE__, __LINE__);
    }

    // initialize the memory
    //
    for (long i=0; i < (long)capacity_a; i++) {
      new_mem[i] = (TObject*)NULL;
    }
    
    // if there are valid elements and we need to preserve them
    //
    if (((long)length_d > 0) && preserve_values_a) {
      for (long i = 0; i < (long)length_d; i++) {
	new_mem[i] = accessByMode(v_d[i]);
      }
    }
    
    // delete the old memory
    //
    if (v_d != (TObject**)NULL) {
      if (alloc_d == SYSTEM) {
	for (long i=0; i < (long)length_d; i++) {
	  if (v_d[i] != (TObject*)NULL) {
	    delete v_d[i];
	    v_d[i] = (TObject*)NULL;
	  }
	}
      }      
      delete [] v_d;
      v_d = (TObject**)NULL;
    }
    
    // assign the pointer to the new memory
    //
    v_d = new_mem;
  }
  
  // set the new capacity
  //
  capacity_d = capacity_a;

  // exit gracefully
  //
  return true;
}

//---------------------------------------------------------------------------
//
// class-specific public methods:
//  queue property methods
//
//---------------------------------------------------------------------------

// method: push
// 
// arguments:
//  TObject* item: (input) item to be inserted
//  COMPARE_FUNC comp_func: (input) priority queue comparison function
//   
// return: a boolean value indicating status
//
// this method inserts an item into the queue
//
template<class TObject>
boolean PriorityQueue<TObject>::push(TObject* item_a,
				     COMPARE_FUNC comp_func_a) {

  // declare local variables
  //
  TObject* new_obj = (TObject*)NULL;

  // mode: SYSTEM
  //  make a copy of the element
  //
  if (alloc_d == SYSTEM) {
    new_obj = new TObject(*item_a);
  }

  // mode: USER
  //  make a copy of the pointer to the item
  //
  else {
    new_obj = item_a;
  }
  
  // increase the size of the heap by one
  //
  setLength((long)length_d + 1);

  // propagate the item up the heap until the heap properties are met
  //
  long i = (long)length_d - 1;
  while ((i > 0) &&
	 (comp_func_a(v_d[parent(i)], new_obj) == Integral::LESSER)) {
    v_d[i] = v_d[parent(i)];
    i = parent(i);
  }
  v_d[i] = new_obj;

  // exit gracefully
  //
  return true;
}

// method: pop
// 
// arguments:
//  TObject* item: (output) item to be removed
//   
// return: a boolean value indicating status
//
// this method removes the maximum item from the queue
//
template<class TObject>
TObject* PriorityQueue<TObject>::pop(TObject* item_a) {

  // declare local variables
  //
  TObject* ptr = (TObject*)NULL;
  
  // when in SYSTEM mode the item passed in should not be
  // null, if we are in USER mode the item should be null
  //
  if (((alloc_d == SYSTEM) && (item_a == (TObject*)NULL)) ||
      ((alloc_d == USER) && (item_a != (TObject*)NULL))) {
    Error::handle(name(), L"remove", ERR, __FILE__, __LINE__);
    return (TObject*)NULL;
  }
  
  // check for heap size violations
  //
  if (!isEmpty()) {

    // retrieve the maximum item form the heap
    //
    ptr = v_d[0];

    // mode: SYSTEM
    //
    if (alloc_d == SYSTEM) {

      // make a copy of the object
      //
      item_a->assign(*ptr);

      // delete the reference to the object      
      //
      delete ptr;
    }
    
    // mode: USER
    //
    else {
      
      // assign the pointer to the item
      //
      item_a = ptr;
    }
    
    // remove the maximum item and reorganize the heap
    //
    v_d[0] = v_d[(long)length_d - 1];
    setLength((long)length_d - 1);
    heapify(0);
    
    // return a pointer to the object (so that the return value can
    // be compared)
    //
    return item_a;
  }

  // nothing in queue, return null
  //
  return (TObject*)NULL;  
}

// method: top
// 
// arguments:
//  TObject* item: (output) item to be removed
//   
// return: a boolean value indicating status
//
// this method removes the maximum item from the queue
//
template<class TObject>
const TObject* PriorityQueue<TObject>::top() const {

  // check for heap size violations
  //
  if (isEmpty()) {
    Error::handle(name(), L"top", Error::ARG, __FILE__, __LINE__);
    return (TObject*)NULL;
  }

  // return the maximum item in the heap
  //
  return v_d[0];
}

// method: top
// 
// arguments:
//  TObject* item: (output) item to be removed
//   
// return: a boolean value indicating status
//
// this method removes the maximum item from the queue
//
template<class TObject>
TObject* PriorityQueue<TObject>::top() {

  // check for heap size violations
  //
  if (isEmpty()) {
    Error::handle(name(), L"top", Error::ARG, __FILE__, __LINE__);
    return (TObject*)NULL;
  }

  // return the maximum item in the heap
  //
  return v_d[0];
}

//---------------------------------------------------------------------------
//
// heap manipulation methods
//
//---------------------------------------------------------------------------

// method: compare
// 
// arguments:
//  TObject* item1: (input) first item to compare
//  TObject* item2: (input) second item to compare
//   
// return: an enum indicating comparison status
//
// method compares the input items
//
template<class TObject>
Integral::COMPARE PriorityQueue<TObject>::compare(TObject* item1_a,
						  TObject* item2_a) {

  // check if item1 is greater than item2
  //
  if (*item1_a > *item2_a) {
    return Integral::GREATER;
  }

  // check if item1 is less than item2
  //
  if (*item1_a < *item2_a) {
    return Integral::LESSER;
  }

  // if we made it this far then the item must be equal
  //
  return Integral::EQUAL;
}
 
// method: heapify
// 
// arguments:
//  long index: (input) index at which o start the heapify process
//  COMPARE_FUNC comp_func: (input) priority queue comparison function
//   
// return: a boolean value indicating status
//
// this method verifies that the underlying array obeys the heap property
//
template<class TObject>
boolean PriorityQueue<TObject>::heapify(long index_a,
					COMPARE_FUNC comp_func_a) {

  // declare local variables
  //
  TObject* tmp = (TObject*)NULL;

  // get the children of the index
  //
  long l = left(index_a);
  long r = right(index_a);

  // assume the current index is the largest
  //
  long largest = index_a;

  // check if the left child is larger
  //
  if ((l < (long)length_d) &&
      (comp_func_a(v_d[l], v_d[index_a]) == Integral::GREATER)) {
    largest = l;
  }

  // check if the right child is larger
  //
  if ((r < (long)length_d) &&
      (comp_func_a(v_d[r], v_d[largest]) == Integral::GREATER)) {
    largest = r;
  }

  // check if the heap property is violated
  //
  if (largest != index_a) {

    // exchange
    //
    tmp = v_d[largest];
    v_d[largest] = v_d[index_a];
    v_d[index_a] = tmp;

    // recursively reorder the heap
    //
    heapify(largest);
  }
  
  // exit gracefully
  //
  return true;
}

// method: buildHeap
// 
// arguments: none
//   
// return: a boolean value indicating status
//
// this method builds a heap out of the underlying array
//
template<class TObject>
boolean PriorityQueue<TObject>::buildHeap() {

  // build the heap using the heapify routine
  //
  long size = (long)length_d - 1;
  for (long i=size/2; i >= 0; i--) {
    heapify(i);
  }
  
  // exit gracefully
  //
  return true;
}

// method: heapSort
// 
// arguments: none
//   
// return: a boolean value indicating status
//
// this method sorts the elements in the heap
//
template<class TObject>
boolean PriorityQueue<TObject>::heapSort() {

  // declare local variables
  //
  long size = (long)length_d;
  TObject* tmp = (TObject*)NULL;

  // construct the heap out of the existing elements
  //
  buildHeap();

  // loop over the elements and sort them as we move along
  //
  for (long i=(long)length_d - 1; i >= 1; i--) {

    // exchange
    //
    tmp = v_d[0];
    v_d[0] = v_d[i];
    v_d[i] = tmp;

    // reduce the size of the heap and reorder
    //
    setLength((long)length_d - 1);
    heapify(0);
  }

  // reset the length after we are done
  //
  setLength(size);
  
  // exit gracefully
  //
  return true;
}

// method: accessByMode
// 
// arguments:
//   TObject* item: (input) input item to access by mode
//   
// return: input item accessed by mode
//
// this method accesses the input element via the access mode
//
template<class TObject>
TObject* PriorityQueue<TObject>::accessByMode(TObject* item_a) {

  // declare local variables
  //
  TObject* new_obj = (TObject*)NULL;

  // access by mode
  //
  if (alloc_d == USER) {
    new_obj = item_a;
  }
  else {
    new_obj = new TObject(*item_a);
  }

  // return the item by mode
  //
  return new_obj;
}

// end of include file
//
#endif
