#include "vector.h"
#include "MenuDriver.h"
#include <iostream>
#include <stdexcept>
using namespace std;
using namespace KW;

class Driver : public MenuDriver {

public:

  Driver(int argc, const char* argv[])
    : MenuDriver(argc,argv)
  {
    stringstream menu;
    menu << "(At)  at(i)" << endl;
    menu << "(As)  at(i) = val" << endl;
    menu << "(Ci)  contains(val)" << endl;
    menu << "(Cu)  count(val)" << endl;
    menu << "(Em)  empty()" << endl;
    menu << "(Er)  erase(i)" << endl;
    menu << "(Ix)  index(val)" << endl;
    menu << "(In)  insert(i,val)" << endl;
    menu << "(N)   new (empty) vector" << endl;
    menu << "(O)   output" << endl;
    menu << "(Po)  pop_back()" << endl;
    menu << "(Pu)  push_back(val)" << endl;
    menu << "(Rm)  remove(val)" << endl;
    menu << "(Rv)  reverse()" << endl;
    menu << "(Sz)  size()" << endl;
    menu << "(Q)   Quit" << endl;
    MENU = menu.str();
  }


protected:

  vector<string> v;

  size_t getIndex() {
    return read<size_t>("Enter an index: ");
  }

  string getValue(const string& prompt = "Enter a string: ") {
    return readLine(prompt);
  }

  bool handleChoice(const string& choice) {
    bool goOn = true;

    
    if ((choice == "At") || (choice == "at")) {  // at
      size_t i = getIndex();
      string val;
      try {
	string &item = v.at(i);
	cout << "at("<<i<<") returned " << item << endl;
      } catch (out_of_range& e) {
	cout << "at("<<i<<") threw out_of_range exception" << endl;
      } catch (...) {
	cout << "at("<<i<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "As") || (choice == "as")) { // at(i) = val
      size_t i = getIndex();
      string val = getValue("Assign to what value? ");
      try {
	v.at(i) = val;
      } catch (out_of_range& e) {
	cout << "at("<<i<<") = " << '"' << val << '"' << ", threw out_of_range exception" << endl;
      } catch (...) {
	cout << "at("<<i<<") = " << '"' << val << '"' << ", threw unexpeced exception" << endl;
      }

    } else if ((choice == "Ci") || (choice == "ci")) { // contains(val)
      string val = getValue();
      try {
	bool has = v.contains(val);
	cout << "contains("<<'"'<<val<<'"'<<") returned " << (has ? "true" : "false") << endl;
      } catch (...) {
	cout << "contains("<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "Cu") || (choice == "cu")) { // count(val)
      string val = getValue();
      try {
	int c = v.count(val);
	cout << "count("<<'"'<<val<<'"'<<") returned " << c << endl;
      } catch (...) {
	cout << "count("<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "Em") || (choice == "em")) { // empty()
      try {
	bool emp = v.empty();
	cout << "empty() returned " << (emp ? "true" : "false") << endl;
      } catch (...) {
	cout << "empty() threw unexpected exception" << endl;
      }

    } else if ((choice == "Er") || (choice == "er")) { // erase(i)
      size_t i = getIndex();
      try {
	v.erase(i);
	cout << "erase(" << i << ") completed." << endl;
      } catch (out_of_range& e) {
	cout << "erase(" << i << ") threw out_of_range exception" << endl;
      } catch (...) {
	cout << "erase(" << i << ") threw unexpected exception." << endl;
      }

    } else if ((choice == "Ix") || (choice == "ix")) { // index(val)
      string val = getValue();
      try {
	int ind = v.index(val);
	cout << "index("<<'"'<<val<<'"'<<") returned " << ind << endl;
      } catch (...) {
	cout << "index("<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "In") || (choice == "in")) { // insert(i,val)
      size_t i = getIndex();
      string val = getValue();
      try {
	v.insert(i,val);
	cout << "insert("<<i<<","<<'"'<<val<<'"'<<") completed." << endl;
      } catch (out_of_range& e) {
	cout << "insert("<<i<<","<<'"'<<val<<'"'<<") threw out_of_range exception" << endl;
      } catch (...) {
	cout << "insert("<<i<<","<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "N") || (choice == "n")) { // new
      vector<string> temp;
      v = temp;
      cout << "Vector has been reinitialized to empty." << endl;

    } else if ((choice == "O") || (choice == "o")) { // output
      try {
	cout << v << endl;
      } catch (...) {
	cout << "output operator (<<) cause unexpected exception" << endl;
      }

    } else if ((choice == "Po") || (choice == "po")) { // pop_back()
      try {
	if (!v.empty()) {
	  try {
	    v.pop_back();
	    cout << "pop_back() completed." << endl;
	  } catch (...) {
	    cout << "pop_back() threw unexpected exception" << endl;
	  }
	} else {
	  cout << "Our driver does not allow pop_back on an empty vector." << endl
	       << "(note: STL does not actually perform such error checking itself)" << endl;
	}
      } catch (...) {
	cout << "Before calling pop_back, we testedcalled empty(). " << endl 
	     << "that call threw unexpected exception" << endl;
      }

    } else if ((choice == "Pu") || (choice == "pu")) { // push_back(val)
      string val = getValue();
      try {
	v.push_back(val);
	cout << "push_back("<<'"'<<val<<'"'<<") completed." << endl;
      } catch (...) {
	cout << "push_back("<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "Rm") || (choice == "rm")) { // remove(val)
      string val = getValue();
      try {
	v.remove(val);
	cout << "remove("<<'"'<<val<<'"'<<") completed." << endl;
      } catch (...) {
	cout << "remove("<<'"'<<val<<'"'<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "Rv") || (choice == "rv")) { // reverse()
      try {
	v.reverse();
	cout << "reverse() completed." << endl;
      } catch (...) {
	cout << "reverse() threw unexpected exception" << endl;
      }

    } else if ((choice == "Sz") || (choice == "sz")) { // size()
      try {
	int sz = v.size();
	cout << "size() returned " << sz << endl;
      } catch (...) {
	cout << "size() threw unexpected exception" << endl;
      }
    } else if ((choice == "Q") || (choice == "q")) { // quit
      goOn = false;
    } else {
	cout << "Invalid response (" << choice << ")." << endl;
    }

    return(goOn);
  }

};


int main(int argc, const char* argv[]) {
  Driver d(argc,argv);
  return d.run();
}

