#include "oop.h"
#include "minmax.h"

OrderedCollection::OrderedCollection(int size)
{
  setCollection(new Array(size));
}

oop OrderedCollection::classNew(int size)
{
  return new OrderedCollection(size);
}

oop OrderedCollection::reset(void)
{
  mFirstIndex= mArray->size() / 3;
  mLastIndex= mFirstIndex;
  return this;
}

oop OrderedCollection::setCollection(oop anArray)
{
  mArray= anArray;
  return reset();
}

int OrderedCollection::growSize(void)
{
  return ::max(3, mArray->size() + 1);
}

oop OrderedCollection::makeRoomAtFirst(void)
{
  if (size() == 0)
    {
      mFirstIndex= mLastIndex= mArray->size();
    }
  else
    {
      int count= size();
      int newSize= count + growSize();
      oop newArray= new Array(newSize);
      int out= newSize;
      int in= mLastIndex;
      while (in > mFirstIndex)
	newArray->atPut(--out, mArray->at(--in));
      mArray= newArray;
      mLastIndex= newSize;
      mFirstIndex= mLastIndex - count;
    }
  return this;
}

oop OrderedCollection::makeRoomAtLast(void)
{
  if (size() == 0)
    {
      mFirstIndex= mLastIndex= 0;
    }
  else
    {
      oop newArray= new Array(size() + growSize());
      for (int inOut= mFirstIndex, last= mLastIndex;  inOut < last;  ++inOut)
	newArray->atPut(inOut, mArray->at(inOut));
      mArray= newArray;
    }
  return this;
}

oop OrderedCollection::addFirst(oop newObject)
{
  // Add newObject to the beginning of the receiver.  Answer newObject.
  if (mFirstIndex == 0)
    makeRoomAtFirst();
  mArray->atPut(--mFirstIndex, newObject);
  return newObject;
}

oop OrderedCollection::addLast(oop newObject)
{
  // Add newObject to the end of the receiver.  Answer newObject.
  if (mLastIndex == mArray->size())
    makeRoomAtLast();
  mArray->atPut(mLastIndex++, newObject);
  return newObject;
}

oop OrderedCollection::add(oop newObject)
{
  return addLast(newObject);
}

oop OrderedCollection::removeFirst(void)
{
  // Remove the first element of the receiver and answer it.  If the receiver is
  // empty, create an error notification.
  emptyCheck();
  oop firstObject= mArray->at(mFirstIndex);
  mArray->atPut(mFirstIndex, 0);
  ++mFirstIndex;
  return firstObject;
}

oop OrderedCollection::removeLast(void)
{
  // Remove the last element of the receiver and answer it.  If the receiver is
  // empty, create an error notification.
  emptyCheck();
  --mLastIndex;
  oop lastObject= mArray->at(mLastIndex);
  mArray->atPut(mLastIndex, 0);
  return lastObject;
}

oop OrderedCollection::at(int index)
{
  return mArray->at(mFirstIndex + index);
}

oop OrderedCollection::atPut(int index, oop element)
{
  return mArray->atPut(mFirstIndex + index, element);
}

oop OrderedCollection::insertBefore(oop newObject, int spotIndex)
{
  if (0 == mFirstIndex)
    {
      int delta= spotIndex - mFirstIndex;
      makeRoomAtFirst();
      spotIndex= mFirstIndex + delta;
    }
  --mFirstIndex;
  mArray->replaceFromToWithStartingAt(mFirstIndex, spotIndex - 1, mArray, mFirstIndex + 1);
  return mArray->atPut(spotIndex - 1, newObject);
}

int OrderedCollection::size(void)
{
  return mLastIndex - mFirstIndex;
}

oop OrderedCollection::iterator(void)
{
  return new ArrayIterator(this);
}

