#include "Hand.h"
#include "Card.h"
#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)
  {

    stringstream menu;
    menu << "(E)  Reinitialize Hand to empty." << endl;
    menu << "(I)  insert a Card into a Hand." << endl;
    menu << "(P)  play a Card from a Hand." << endl;
    menu << "(C)  copy constructor." << endl;
    menu << "(A)  assignment operator." << endl;
    menu << "(D)  destructor (then reinitialize)." << endl;
    menu << "(Q)  Quit." << endl;
    MENU = menu.str();

    hand[1] = new Hand();
    hand[2] = new Hand();
    cout << "Welcome.  Empty hands have been created for each of the two players.\n\n";
  }


protected:

  Hand *hand[3];

  int whichHand(const string& prompt) {
    int result;
    do {
      result = read<int>(prompt);
      if (result!=1 && result!=2) {
	cout << "Please enter '1' or '2'\n";
      }
    } while (result != 1 && result != 2);

    return result;
  }

  Card::Value readValue() {
    Card::Value result = Card::NOVALUE;
    do {
      char response = read<char>("Enter the value (i.e. '5', '9', 'A', 'J'):  ");
      result = Card::toValue(toupper(response));
      if (result==Card::NOVALUE) {
	cout << "Value '" << response << "' was not recognized.\n";
      }
    } while (result == Card::NOVALUE);

    return result;
  }



  Card::Suit readSuit() {
    Card::Suit result = Card::NOSUIT;
    do {
      char response = read<char>("Enter the suit (i.e. 'C', 'D', 'H', 'S'):  ");
      result = Card::toSuit(toupper(response));

      if (result==Card::NOSUIT) {
	cout << "Suit '" << response << "' was not recognized.\n";
      }
    } while (result == Card::NOSUIT);

    return result;
  }



  bool handleChoice(const string& choice) {
    string handPrompt = "Which player? (1 or 2)  ";
    bool goOn = true;

    
    if ((choice == "E") || (choice == "e") || (choice == "D") || (choice == "d")) {
      int hIndex = whichHand(handPrompt);
      try {
	if (((choice == "D") || (choice == "d")) && hand[hIndex]!=NULL) // otherwise memory leak
	  delete hand[hIndex];
	try {
	  hand[hIndex] = new Hand();
	  cout << "Hand constructor has been called." << endl;
	} catch (const exception &e) {
	  cout << "constructor threw unexpected exception: " << e.what() << endl;
	} catch (...) {
	  cout << "constructor threw unexpected exception" << endl;
	}

      } catch (const exception &e) {
	cout << "while destructing existing hand, unexpected exception: " << e.what() << endl;
      } catch (...) {
	cout << "while destructing existing hand, unexpected exception." << endl;
      }
    } else if ((choice == "I") || (choice == "i")) {
	int hIndex = whichHand(handPrompt);
	Card::Value value = readValue();
	Card::Suit suit = readSuit();
	Card c(value,suit);
	try {
	  hand[hIndex]->insertCard(c);
	  cout << "insertCard(" << c << ") called.\n";
	} catch (const exception &e) {
	  cout << "insertCard(" << c << ") threw unexpected execption: " << e.what() << endl;
	} catch (...) {
	  cout << "insertCard(" << c << ") threw unexpected execption." << endl;
	}
    } else if ((choice == "P") || (choice == "p")) {
	int hIndex = whichHand(handPrompt);
	Card::Suit suit = readSuit();
	try {
	  Card c = hand[hIndex]->playDown(suit);
	  cout << "playDown(" << Card::toChar(suit) << ") returned " << c << endl;
	} catch (const hand_empty& e) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw hand_empty exception" << endl;
	} catch (const exception& e) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw unexpected exception '" << e.what() << "'\n";
	} catch (...) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw unexpected exception\n";
	}
    } else if ((choice == "A") || (choice == "a")) {
      int srcIndex = whichHand("Which player's hand is to be used as the model? (1 or 2)  ");
      int destIndex = whichHand("Which player's hand is to be reassigned to the model? (1 or 2)  ");
      try {
	hand[0] = hand[destIndex];
	(*hand[destIndex]) = (*hand[srcIndex]);
      } catch (const exception& e) {
	cout << "assignment operator threw unexpected exception: " << e.what() << endl;
	hand[destIndex] = hand[0];
      } catch (...) {
	cout << "assignment operator threw unexpected exception" << endl;
	hand[destIndex] = hand[0];
      }

    } else if ((choice == "C") || (choice == "c")) {
      int srcIndex = whichHand("Which player's hand is to be used as the model? (1 or 2)  ");
      int destIndex = whichHand("Which player's hand is to be replaced by the new copy? (1 or 2)  ");
      hand[0] = hand[destIndex];
      try {
	hand[destIndex] = new Hand(*hand[srcIndex]);
      } catch (const exception& e) {
	cout << "copy constructor threw unexpected exception: " << e.what() << endl;
	hand[destIndex] = hand[0];  // restore prior settings
      } catch (...) {
	cout << "copy constructor threw unexpected exception\n";
	hand[destIndex] = hand[0];  // restore prior settings
      }
    } 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();
}

