using namespace std;

#include <iostream>
#include <cstdlib>

#include "deque.h"

void test1();
void test2();
void test3();
void test4();
void test5();

int main(int argc, char **argv)
{
  const int NUM_TESTS = 5;

  if (argc != 2)
    {
      cerr << "USAGE: " << argv[0] << " test-number" << endl;
      return 1;
    }

  int test = atoi(argv[1]);

  if (test < 1 || test > NUM_TESTS)
    {
      cerr << argv[0] << ": illegal test number" << endl;
      return 1;
    }

  switch (test)
    {
    case 1:
      test1();
      break;

    case 2:
      test2();
      break;

    case 3:
      test3();
      break;

    case 4:
      test4();
      break;

    case 5:
      test5();
      break;
    }

  return 0;
}

void test1()
{
  Deque d0, d1, d2;

  const int TEST_LENGTH = 3;

  cerr << "Testing writeTo and getSize" << endl;
  for (int i = 0; i < TEST_LENGTH; i++)
    d0.addFront(i);
  d0.writeTo(cerr);
  cerr << "size = " << d0.getSize() << endl;
  
  cerr << "Testing add to front and remove from back" << endl;

  for (int i = 0; i < TEST_LENGTH; i++)
    d1.addFront(i);

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;

      d1.removeBack(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }

  cerr << "Testing add to back and remove from front" << endl;

  for (int i = 0; i < TEST_LENGTH; i++)
    d2.addBack(i);

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;

      d2.removeFront(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }
}

void test2()
{
  const int STUB_SIZE = 1;
  const int TEST_LENGTH = 100;

  Deque d1, d2;

  cerr << "Testing wraparound at back" << endl;

  for (int i = 0; i < STUB_SIZE; i++)
    d1.addBack(i);

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      d1.addBack(i + STUB_SIZE);
      
      int item;
      d1.removeFront(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }

  cerr << "Testing wraparound at front" << endl;

  for (int i = 0; i < STUB_SIZE; i++)
    d2.addFront(i);

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      d2.addFront(i + STUB_SIZE);
      
      int item;
      d2.removeBack(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }
}

void test3()
{
  const int TEST_LENGTH = 1000;

  Deque d1, d2;

  cerr << "Testing big deques" << endl;

  for (int i = 0; i < TEST_LENGTH; i++)
    d1.addBack(i);

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;
      d1.removeFront(item);

      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }

  cerr << "Testing mixed front/back operations" << endl;

  for (int i = TEST_LENGTH - 1; i >= 0; i--)
    {
      d2.addFront(i);
      d2.addBack(i);
    }
  
  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;

      d2.removeFront(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;

      d2.removeBack(item);
      if (item != i)
	cerr << " error: removed " << item << " instead of " << i << endl;
    }
}

void test4()
{
  const int TEST_LENGTH = 100;

  Deque d1;

  cerr << "Testing copy constructor" << endl;

  for (int i = 0; i < TEST_LENGTH; i++)
    d1.addFront(i);
  
  {
    Deque d2 = d1;

    for (int i = 0; i < TEST_LENGTH; i++)
      {
	int item;
	d2.removeFront(item);

	if (item != TEST_LENGTH - 1 - i)
	  cerr << " error: removed " << item << " instead of " << i << endl;
      }
  }

  {
    cerr << "Testing copy from" << endl;

    Deque d3;

    for (int i = 0; i < TEST_LENGTH * 2; i++)
      d3.addBack(i);

    d3.copyFrom(d1);

    for (int i = 0; i < TEST_LENGTH; i++)
      {
	int item;
	d3.removeFront(item);

	if (item != TEST_LENGTH - 1 - i)
	  cerr << " error: removed " << item << " instead of " << i << endl;
      }
  }

  cerr << "Checking integrity of original deque" << endl;

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;
      d1.removeBack(item);

      if (item != i)
	  cerr << " error: removed " << item << " instead of " << i << endl;
    }
}

void test5()
{
  const int TEST_LENGTH = 100;

  Deque d1;

  for(int i = 0 ; i < TEST_LENGTH; i++)
    d1.addFront(i);

  cerr << "Testing clone" << endl;
  Deque d2 = d1.clone();

  for (int i = 0; i < TEST_LENGTH; i++)
    {
      int item;
      d2.removeBack(item);

      if (item != i)
	  cerr << " error: removed " << item << " instead of " << i << endl;
    }
}


