#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include "Hand.h"
#include "Card.h"

using namespace std;

istream *isr;
bool echoinput;
bool endOfInput=false;

string GeneralQuestion(const string& prompt) {
  string response;
  bool done = false;

  cout << prompt;
  while (!done) {
    getline(*isr, response);
    if (isr->eof()) {
      // must be EOF
      if (echoinput) {
	// switch to keyboard input
	isr = &cin;
	echoinput=false;
      } else {
	cout << "unexpected end of input reached.\n";
	endOfInput = true;
	done=true;
      }
    } else {
      // successful so far
      if (echoinput) cout << response << "\n";
      if ((response).length()>0) done=true;
    }
  }

  return(response);
}



int whichHand(const string& prompt) {
  int result = -1;
  string response;
  do {
    response = GeneralQuestion(prompt);
    result = atoi(response.c_str());

    if (result!=1 && result!=2) {
      cout << "Value '" << response << "' was not recognized. Please enter '1' or '2'\n";
    }
  } while (result != 1 && result != 2);

  return result;
}



Card::Value readValue() {
  Card::Value result = Card::NOVALUE;
  string response;
  do {
    string prompt = "Enter the value (i.e. '5', '9', 'A', 'J'):  ";
    response = GeneralQuestion(prompt);
    result = Card::toValue(toupper(response[0]));

    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;
  string response;
  do {
    response = GeneralQuestion(string("Enter the suit (i.e. 'C', 'D', 'H', 'S'):  "));
    result = Card::toSuit(toupper(response[0]));

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

  return result;
}


int main(int argc, const char* argv[]) {
  string MENU = "Valid commands include:\n(E)  Reinitialize a Hand to empty.\n(I)  insert a Card into a Hand.\n(P)  play a Card from a Hand.\n(C)  copy one hand to another.\n(A)  assign one hand to another.\n(Q)  Quit.\n\nExtra Credit commands include:\n(D)  display a Hand\n(S)  display a single suit from a Hand\n";

  filebuf fb;
  bool quit = false;
  int command=1;
  string response;
  char choice;

  Hand *hand[3];   // hand[0] is temp location;  hand[1] and hand[2] are players
  hand[1] = new Hand();
  hand[2] = new Hand();
  int hIndex,srcIndex,destIndex;

  // choose between keyboard input or mock-keyboard file input
  echoinput = false;
  isr = &cin;
  if (argc>1) {
    fb.open(argv[1],ios::in);
    if (fb.is_open()) {
      isr = new istream(&fb);
      echoinput= true;
    } else {
      cout << "Input file '" << argv[1] << "' not found.\n";
      cout << "Defaulting to keyboard input.\n\n";
    }
  }


  // is there a limit on the number of lines to read?
  int LIMIT = -1;
  if (argc>2) {
    LIMIT = atoi(argv[2]);
    if (LIMIT < 1) {
      LIMIT = -1;
      cout << "Second argument (" << argv[2] << ") ignored.\n\n";
    }
  }


  cout << "Welcome.  Empty hands have been created for each of the two players.\n\n";
  string handPrompt = "Which player? (1 or 2)  ";

  cout << MENU << "\n";
  do {
    Card::Value value;
    Card::Suit suit;
    Card c;
    char temp[50];
    sprintf(temp,"\nCommand #%i> ",command);
    response = GeneralQuestion(string(temp));
    command++;

    choice = response[0];


    switch (choice)
      {
      case 'e':
      case 'E':
	hIndex = whichHand(handPrompt);
	if (hand[hIndex]!=NULL) delete hand[hIndex];
	hand[hIndex] = new Hand();
	cout <<  "Hand constructor called for player.\n";
	break;

      case 'i':
      case 'I':
	hIndex = whichHand(handPrompt);
	value = readValue();
	suit = readSuit();
	c = Card(value,suit);
	try {
	  hand[hIndex]->insertCard(c);
	  cout << "insertCard(" << c << ") called.\n";
	} catch (...) {
	  cout << "insertCard(" << c << ") threw unexpected execption.\n";
	}
	break;

      case 'p':
      case 'P':
	hIndex = whichHand(handPrompt);
	suit = readSuit();
	try {
	  Card c = hand[hIndex]->playDown(suit);
	  cout << "playDown(" << Card::toChar(suit) << ") returned " << c << endl;
	} catch (const EmptyHandException& e) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw EmptyHandException\n";
	} catch (const RuntimeException& e) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw unexpected exception '" << e << "'\n";
	} catch (...) {
	  cout << "playDown(" << Card::toChar(suit) << ") threw unexpected exception\n";
	}
	break;

	
      case 'a':
      case 'A':
	srcIndex = whichHand("Which player's hand is to be used as the model? (1 or 2)  ");
	destIndex = whichHand("Which player's hand is to be reassigned to the model? (1 or 2)  ");
	(*hand[destIndex]) = (*hand[srcIndex]);
	break;


      case 'c':
      case 'C':
	srcIndex = whichHand("Which player's hand is to be used as the model? (1 or 2)  ");
	destIndex = whichHand("Which player's hand is to be replaced by the new copy? (1 or 2)  ");
	hand[0] = hand[destIndex];
	hand[destIndex] = new Hand(*hand[srcIndex]);
	delete hand[0];
	break;


      case 'd':
      case 'D':
	{
	  hIndex = whichHand(handPrompt);
	  Hand::Iterator it = hand[hIndex]->allCards();
	  cout << "Currrent hand: ";
	  while (it.hasNext()) {
	    Card c = it.next();
	    cout << c;
	    if (it.hasNext())
	      cout << ", ";
	  }
	  cout << endl;
	}
	break;


      case 's':
      case 'S':
	{
	  hIndex = whichHand(handPrompt);
	  Card::Suit suit = readSuit();
	  Hand::Iterator it = hand[hIndex]->allOfSuit(suit);
	  cout << "allOfSuit(" << Card::suitName(suit) << "):  ";
	  while (it.hasNext()) {
	    Card c = it.next();
	    cout << c;
	    if (it.hasNext())
	      cout << ", ";
	  }
	  cout << endl;
	}
	break;

      case 'q':
      case 'Q':
	quit = true;
	break;

      default:
	cout << "Unrecognized option: " << choice << "\n";
	cout << MENU << "\n";
      }
  } while (!quit  && (LIMIT<0 || command<LIMIT));


  cout << "\n";
  if (isr != &cin)  delete isr;

  cout << "Calling Destructor for the players' hands...\n";
  if (hand[1]!=NULL) delete hand[1];
  if (hand[2]!=NULL) delete hand[2];
  cout << "Goodbye.\n";

  

  return(0);
}





