/**
 * Sorted list implementation modified to use a dynamically allocated
 * array instead of a statically allocated array.
 *
 * Changes are noted with // comments
 */

using namespace std;

#include <cassert>

#include "list.h"

/**
 * Constructs an empty list.
 */

List::List()
{
  // dynamically allocate array
  maxItems = 4;
  items = new ItemType[maxItems];

  numItems = 0;
  currentIndex = -1;
}

/**
 * Destroys this list
 */

List::~List()
{
  // release dynamically allocated memory
  delete[] items;
}

/**
 * pre: none
 * post: returns true iff the list is full.
 */

bool List::isFull() const
{
  // we can always resize the array, so the list is never full
  return false;
}

/**
 * pre: none
 * post: returns the number of items on the list.
 */

int List::getLength() const
{
  return numItems;
}

/**
 * pre: none
 * post: if item with same key as i is on the list, then that item is
 * copied into i and found = true, otherwise i is unchanged and i = false
 */

void List::retrieveItem(ItemType& i, bool& found) const
{
  int loc;

  binarySearch(i, loc, found);

  if (found)
    i = items[loc];
}

/**
 * pre: none
 * post: the list is empty
 */

void List::makeEmpty()
{
  currentIndex = -1;
  numItems = 0;

  // make array smaller (but not too small -- some C++ implementations have
  // problems with arrays of size 0)
  delete[] items;
  maxItems = 1;
  items = new ItemType[maxItems];
}

/**
 * pre: no item with same key as toAdd is on the list and the list isn't full
 * post: item toAdd has been added to the list and items sorted by key
 */

void List::addItem(const ItemType& toAdd)
{
  // if array is full then resize it  
  if (numItems == maxItems)
    {
      // make new array
      maxItems *= 2;
      ItemType* newArr = new ItemType[maxItems * 2];
      assert(newArr != NULL);

      // copy from old array to new array
      for (int i = 0; i < numItems; i++)
	newArr[i] = items[i];

      // release old array
      delete[] items;

      // remember new array
      items = newArr;
    }

  int insertLoc;
  bool found;

  binarySearch(toAdd, insertLoc, found);

  for (int copyTo = numItems; copyTo >= insertLoc + 1; copyTo--)
    items[copyTo] = items[copyTo - 1];

  items[insertLoc] = toAdd;
  numItems++;
}

/**
 * pre: an item with same key as toDelete is on the list
 * post: that item is no longer on the list and the current point is set to
 * the beginning of the list and items still sorted by key
 */

void List::deleteItem(const ItemType& toDelete)
{
  int deletePos;
  bool found;

  binarySearch(toDelete, deletePos, found);

  assert(found);

  for (int copyTo = deletePos; copyTo < numItems - 1; copyTo++)
    items[copyTo] = items[copyTo + 1];

  numItems--;
  currentIndex = -1;

  // maybe here we should resize the array if there's too much unused space?
}

/**
 * pre: none
 * post: the current position in the list is the beginning of the list
 */

void List::resetCurrent()
{
  currentIndex = -1;
}

/**
 * pre: there is a next item on the list
 * post: the current position is advanced one spot and the item moved over
 * is copied to nextItem
 */

void List::getNextItem(ItemType& nextItem)
{
  currentIndex++;
  nextItem = items[currentIndex];
}

/**
 * pre: none
 * post: if an item matching the key given is found, found is set to true
 * and loc is set to the location of the item; otherwise found is set to false
 * and loc is set to the location where the item should be inserted
 */

void List::binarySearch(const ItemType& key, int& loc, bool& found) const
{
  int first = 0;
  int last = numItems - 1;
  int mid = (first + last) / 2;
  
  while (first < last && items[mid].compareTo(key) != 0)
    {
      if (items[mid].compareTo(key) < 0)
	first = mid + 1;
      else
	last = mid - 1;
      
      mid = (first + last) / 2;
    }
  
  if (last < first || items[mid].compareTo(key) > 0)
    {
      found = false;
      loc = first;
    }
  else if (items[mid].compareTo(key) < 0)
    {
      found = false;
      loc = first + 1;
    }
  else
    {
      found = true;
      loc = mid;
    }
}


