#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <assert.h>
#include "undoarray.h"

using namespace std;

// helper testing function
void SimpleTest();
void BatchTest(const char* filename, int num);

int main(int argc, char* argv[]) {

  SimpleTest();
  cout << "Simple test passed." << endl;
   
  //
  // you should add your own test cases here.  
  // be sure to test:
  //   * undo arrays that store types other than char
  //   * copy constructor
  //   * assignment operator
  //   * delete operator
  //

  if (argc > 1) {
    assert (argc == 3);
    BatchTest(argv[1],atoi(argv[2]));
    cout << "Batch test completed." << endl;
  }
}


void SimpleTest() {
  // create an undo array of chars of length 7
  UndoArray<char> ua(7);
  for (int i = 0; i < 7; i++) {
    assert (ua.initialized(i) == false);
  }

  // do some operations to verify the performance
  ua.set(2,'a');
  assert (ua.initialized(2) == true);
  assert (ua.get(2) == 'a');
  ua.set(2,'b');
  assert (ua.initialized(2) == true);
  assert (ua.get(2) == 'b');
  ua.set(4,'c');
  assert (ua.initialized(4) == true);
  assert (ua.get(4) == 'c');

  cout << ua;

  ua.undo(2);
  assert (ua.get(2) == 'a');
  assert (ua.get(4) == 'c');
  ua.undo(4);
  assert (ua.initialized(4) == false);  
  assert (ua.initialized(2) == true);  
  assert (ua.get(2) == 'a');

  cout << ua;

  // note...  the UndoArray destructor is implicitly called for the
  // variable 'ua' when we leave the function and it goes out of scope
}


// Batch test will repeatedly load & process a file with UndoArray
// operations.  If the program's working memory does not grow when the
// program is run many, many times on a large test case, the data
// structure is probably free of memory leaks.
void BatchTest(const char* filename, int num) {
  assert (num > 0);

  while (num > 0) {
    num--;

    // open the file stream for reading
    ifstream istr(filename);
    assert (istr);

    // read the size of the array to allocate
    char c;
    int i;
    istr >> c >> i;
    assert (c == 'a');
    // here we explicitly allocate memory for the UndoArray object
    UndoArray<char> *ua = new UndoArray<char>(i);

    // read in and perform various operations on the array
    while (istr >> c) {
      if (c == 's') {
	istr >> i >> c;
	ua->set(i,c);	
      } else if (c == 'g') {
	istr >> i;
	if (ua->initialized(i)) {
	  char val = ua->get(i);	
	}
      } else {
	assert (c == 'u');
	istr >> i;
	if (ua->initialized(i)) {
	  ua->undo(i);	
	}
      }
    }

    // Because the UndoArray memory was allocated explicitly (using new)
    // we need to explicitly deallocate the memory (using delete)
    delete ua;
  }
}



