/**
 * list.cpp
 * Jim Glenn 10/25/2002
 *
 * Sorted list implementation modified to add a copy function and a
 * copy constructor.  Additions since last modification (changing to
 * dynamically allocated array) are noted with // comments
 */

using namespace std;

#include <cassert>

#include "list.h"

/**
 * Constructs an empty list.
 */

List::List()
{
  maxItems = 4;
  items = new ItemType[maxItems];

  numItems = 0;
  currentIndex = -1;
}

/**
 * Constructs a list containing the same elements in the same order as
 * the parameter list.
 */

List::List(const List& toCopy)  // must be a & parameter; should be const
{
  // allocate array to same size as parameter's
  items = new ItemType[toCopy.maxItems];

  // copy from parameter's array into own
  for (int i = 0; i < toCopy.numItems; i++)
    items[i] = toCopy.items[i];

  // copy other instance variables
  maxItems = toCopy.maxItems;
  numItems = toCopy.numItems;

  // the copy constructor will get used automatically to create copies for
  // value parameters and return values
}

/**
 * Destroys this list
 */

List::~List()
{
  delete[] items;
}

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

bool List::isFull() const
{
  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;

  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)
{
  // worst case O(n) time for the following if (since we might have
  // tocopy everything), but amortized O(1) time since _total_ work
  // done by this if for O(n) addItems is O(n)

  if (numItems == maxItems)
    {
      maxItems *= 2;
      ItemType* newArr = new ItemType[maxItems * 2];
      assert(newArr != NULL);

      for (int i = 0; i < numItems; i++)
	newArr[i] = items[i];

      delete[] items;

      items = newArr;
    }

  int insertLoc;
  bool found;

  // O(log n) work here

  binarySearch(toAdd, insertLoc, found);

  // worst case O(n) work here (total=amortized O(1) + O(log n) + O(n) = O(n))

  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;
}

/**
 * copys elements from parameter to this list, overwriting old elements
 */

void List::copyFrom(const List& toCopy)
{
  // check for self-copy; if self-copy then nothing to do
  if (this != &toCopy)
    {
      // make new array
      ItemType* newArr = new ItemType[toCopy.maxItems];
      
      // copy from parameter's array into new array
      for (int i = 0; i < toCopy.numItems; i++)
	newArr[i] = toCopy.items[i];

      // delete old array
      delete[] items;

      // remember new one
      items = newArr;

      // copy other instance variables
      maxItems = toCopy.maxItems;
      numItems = toCopy.numItems;
    }

  // the copyFrom method can now be used in place of = (or overload = based
  // on this code) -- for example, "l1 = l2;" should be replaced by
  // "l1.copyFrom(l2);"
}

/**
 * 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;
    }
}

