#include <iostream>
#include <fstream>
#include <stdexcept>
#include "matrix.h"
using namespace std;

int main() {


  // Perform tests for range.size.  Only produce output if there is an error
  {
    struct testcase {
      string label;
      range r;
      int ans;
    };

    testcase tests[] = {
      { "range(17)",        range(17),        1 },    // 17
      { "range(1,5)",       range(1,5),       4 },    // 1,2,3,4
      { "range(1,1)",       range(1,1),       0 },    // empty
      { "range(5,15)",      range(5,15),     10 },    // 5,6,7,8,9,10,11,12,13,14
      { "range(1,2,3)",     range(1,2,3),     1 },    // 1
      { "range(1,2,4)",     range(1,2,4),     2 },    // 1,3
      { "range(1,2,5)",     range(1,2,5),     2 },    // 1,3
      { "range(1,2,6)",     range(1,2,6),     3 },    // 1,3,5
      { "range(3,3,3)",     range(3,3,3),     0 },    // empty
      { "range(3,3,4)",     range(3,3,4),     1 },    // 3
      { "range(3,3,5)",     range(3,3,5),     1 },    // 3
      { "range(3,3,6)",     range(3,3,6),     1 },    // 3
      { "range(3,3,7)",     range(3,3,7),     2 },    // 3,6
    };
    int numTests = sizeof(tests) / sizeof(tests[0]);

    for (int t = 0; t < numTests; t++) {
      int junk;
      junk = tests[t].r.size();
      if (junk != tests[t].ans)
	cout << "Error: " << tests[t].label << ".size() returned " << junk << " rather than " << tests[t].ans << endl;
    }
  }



  // perform tests based on a matrix read from a file
  fstream fin;

  do {
    if (fin.fail()) {
      cout << "Unable to open file." << endl;
      fin.clear();
    }
    string filename;
    cout << "Enter filename containing origin matrix: ";
    cin >> filename;
    fin.open(filename.c_str());
  } while (fin.fail());

  matrix A;
  fin >> A;

  cout << "Matrix A was read as:" << endl;
  cout << A << endl;



  // Perform tests using standard indices
  {
    struct testcase {
      string rowLabel;
      int r;
      string colLabel;
      int c;
    };

    testcase tests[] = {
      {   "2",     2,     "4",     4 },
      { "100",   100,   "100",   100 },
    };
    int numTests = sizeof(tests) / sizeof(tests[0]);

    for (int t = 0; t < numTests; t++) {
      try {
	double val = A(tests[t].r, tests[t].c);
	cout << "A(" << tests[t].r << ", " << tests[t].c << ") returned " << val << endl;
      } catch (const out_of_range& ex) {
	cout << "A(" << tests[t].r << ", " << tests[t].c << ") thew exception: " << ex.what() << endl;
      }
      cout << endl;
    }
  }


  // Perform tests for submatrices based on range
  {
    struct testcase {
      string rowLabel;
      range rows;
      string colLabel;
      range cols;
    };


    // feel free to add more tests here...make sure labels match ranges
    testcase tests[] = {
      {  "range(3)",       range(3),      "range(2,7)",         range(2,7)       },
      {  "range(3,5)",     range(3,5),    "range(2,3,10)",      range(2,3,10)    },
      {  "range(3,5)",     range(3,5),    "range(2,3,100)",     range(2,3,100)   },
    };
    int numTests = sizeof(tests) / sizeof(tests[0]);

    for (int t = 0; t < numTests; t++) {
      try {
	matrix junk = A(tests[t].rows, tests[t].cols);
	cout << "A(" << tests[t].rowLabel << ", " << tests[t].colLabel << ") returned " << endl;
	cout << junk << endl;
      } catch (const out_of_range& ex) {
	cout << "A(" << tests[t].rowLabel << ", " << tests[t].colLabel << ") threw exception: " << ex.what() << endl;
      }
    }
  }
}
