#ifndef EXTRA
#include "editor.h"
#else
#include "editorExtra.h"
#endif

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

bool HEADTOHEAD;

class Driver : public MenuDriver {

public:

  Driver(int argc, const char* argv[])
    : MenuDriver(argc,argv), text(new editor())
  {
    stringstream menu;
    menu << "(f)   forward" << endl;
    menu << "(b)   backward" << endl;
    menu << "(<)   begin" << endl;
    menu << "(>)   end" << endl;
    menu << "(a)   assign value" << endl;
    menu << "(i)   insert" << endl;
    menu << "(e)   erase" << endl;
    menu << "(t)   toString" << endl;
    menu << endl;
#ifndef COMPETE
    menu << "(d)   raw dump" << endl;
    menu << endl;
#endif
#ifdef EXTRA
    menu << "(m)   setMark" << endl;
    menu << "(c)   cut" << endl;
    menu << "(p)   paste" << endl;
    menu << endl;
#endif
    menu << "(n)   reinitialize new editor" << endl;
    menu << "(q)   quit" << endl;
    MENU = menu.str();
  }


protected:

  editor *text;

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

    
    if ((choice == "f") || (choice == "F")) {
      try {
	text->forward();
	cout << "forward() was called." << endl;
      } catch (exception &e) {
	cout << "forward() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "forward() threw unexpected exception" << endl;
      }
    } else if ((choice == "b") || (choice == "B")) {
      try {
	text->backward();
	cout << "backward() was called." << endl;
      } catch (const exception &e) {
	cout << "backward() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "backward() threw unexpected exception" << endl;
      }
    } else if (choice == "<") {
      try {
	text->begin();
	cout << "begin() was called." << endl;
      } catch (const exception &e) {
	cout << "begin() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "begin() threw unexpected exception" << endl;
      }
    } else if (choice == ">") {
      try {
	text->end();
	cout << "end() was called." << endl;
      } catch (const exception &e) {
	cout << "end() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "end() threw unexpected exception" << endl;
      }
    } else if ((choice == "a") || (choice == "a")) {
      char c = read<char>("Enter a character: ");
      try {
	text->assign(c);
	cout << "assign() was called." << endl;
      } catch (const exception &e) {
	cout << "assign("<<c<<") threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "assign("<<c<<") threw unexpected exception" << endl;
      }

    } else if ((choice == "i") || (choice == "i")) {
      char c = read<char>("Enter a character: ");
      try {
	text->insert(c);
	cout << "insert("<<c<<") was called." << endl;
      } catch (const bad_alloc &ba) {
	cout << "insert("<<c<<") threw bad_alloc exception." << endl;
      } catch (const exception &e) {
	cout << "insert("<<c<<") threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "insert("<<c<<") threw unexpected exception" << endl;
      }
    } else if ((choice == "e") || (choice == "E")) {
      try {
	text->erase();
	cout << "erase() was called." << endl;
      } catch (const exception &e) {
	cout << "erase() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "erase() threw unexpected exception" << endl;
      }
    } else if ((choice == "t") || (choice == "T")) {
      try {
	cout << "toString() returns: " << '"' << text->toString() << '"' << endl;
      } catch (const exception &e) {
	cout << "toString() threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "toString() threw unexpected exception" << endl;
      }
    } else if ((choice == "d") || (choice == "D")) {
      if (!HEADTOHEAD) {
	try {
	  text->rawDump(cout);
	} catch (const exception &e) {
	  cout << "rawDump(cout) threw unexpected exception: " << e.what() << endl;
	} catch (...) {
	  cout << "rawDump(cout) threw unexpected exception" << endl;
	}
      } else
	cout << "rawDump() cannot be called in head-to-head mode." << endl;
#ifdef EXTRA
    } else if ((choice == "m") || (choice == "M")) {
      if (!HEADTOHEAD) {
	try {
	  text->setMark();
	  cout << "setMark() was called." << endl;
	} catch (const exception &e) {
	  cout << "setMark() threw unexpected exception: " << e.what() << endl;
	} catch (...) {
	  cout << "setMark() threw unexpected exception" << endl;
	}
      } else
	cout << "setMark() cannot be called in head-to-head mode." << endl;
    } else if ((choice == "c") || (choice == "C")) {
      if (!HEADTOHEAD) {
	try {
	  text->cut();
	  cout << "cut() was called." << endl;
	} catch (const exception &e) {
	  cout << "cut() threw unexpected exception: " << e.what() << endl;
	} catch (...) {
	  cout << "cut() threw unexpected exception" << endl;
	}
      } else
	cout << "cut() cannot be called in head-to-head mode." << endl;
    } else if ((choice == "p") || (choice == "P")) {
      if (!HEADTOHEAD) {
	try {
	  text->paste();
	  cout << "paste() was called." << endl;
	} catch (const exception &e) {
	  cout << "paste() threw unexpected exception: " << e.what() << endl;
	} catch (...) {
	  cout << "paste() threw unexpected exception" << endl;
	}
      } else
	cout << "paste() cannot be called in head-to-head mode." << endl;
#endif
    } else if ((choice == "N") || (choice == "n")) {
      size_t sz = read<size_t>("Enter maximum number of characters: ");
      try {
	delete text;
      } catch (const exception &e) {
	cout << "destructor threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "destructor threw unexpected exception" << endl;
      }

      try {
	text = new editor(sz);
	cout << "editor has been reinitialized." << endl;
      } catch (const exception &e) {
	cout << "editor(" << sz << ") threw unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "editor(" << sz << ") 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[]) {
  HEADTOHEAD = (argc>3);
  Driver d(argc,argv);
  return d.run();
}

