#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include <istream>
#include <iostream>
#include <fstream>
#include <string>
#include "BoundedStack.h"
#include "BoundedStackA.h"
#include "BoundedStackB.h"

using namespace std;

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



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

  if (prompt)
    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;
	answer = NULL;
	done=true;
      }
    } else {
      // successful so far
      if (echoinput) cout << response << "\n";
      if ((response).length()>0) done=true;
    }
  }

  if (answer) {
    answer = new string(response);
  }

  return(answer);
}




bool valid(BoundedStack *bs) {
  if (bs==NULL) {
    cout << "The history has not yet been properly initialized.\n";
    return(false);
  } else {
    return(true);
  }

}


int main(int argc, const char* argv[]) {
  string MENU = "Valid commands include:\n(A)  create or reinitialize with BoundedStackA.\n(B)  create or reinitialize with BoundedStackB.\n(S)  call size.\n(E)  call isEmpty.\n(U)  call Push.\n(P)  call Pop\n(T)  call Top\n(Q)  Quit.";


  filebuf fb;
  bool quit = false;
  int value;
  int i;
  int command=1;
  string *response;
  string answer;
  char choice;

  BoundedStack *BS = NULL;

  // 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 << MENU << "\n";
  do {
    char temp[50];
    sprintf(temp,"\nCommand #%i> ",command);
    response = GeneralQuestion(new string(temp));
    command++;

    if (response==NULL) {	
      choice = 'q';
    } else {
      choice = (*response)[0];
      if (response) delete response;
    }


    switch (choice)
      {
      case 'a':
      case 'A':
      case 'b':
      case 'B':
	response = GeneralQuestion(new string("Enter a capacity for the history: "));

	if (!response) {
	    cout << "Invalid capacity.  Aborting command.\n";
	} else {
	  value = atoi((*response).c_str());
	  delete response;

	  if (value<1) {
	    cout << "Invalid capacity.  Aborting command.\n";
	  } else {
	    if ((choice=='a') || (choice=='A')) {
	      BS = new BoundedStackA(value);
	      cout <<  "BoundedStackA constructor called with capacity " << value << "\n";
	    } else {
	      BS = new BoundedStackB(value);
	      cout << "BoundedStackB constructor called with capacity " << value << "\n";
	    }
	  }
	}
	break;

      case 's':
      case 'S':
	if (valid(BS)) {
	  i = (*BS).size();
	  cout << "size( ) returned " << i << "\n";
	}
	break;

      case 'e':
      case 'E':
	if (valid(BS)) {
	  bool s = (*BS).isEmpty();
	  cout << "isEmpty( ) returned " << (s ? "true" : "false") << "\n";
	}
	break;

      case 'u':
      case 'U':
	if (valid(BS)) {
	  response = GeneralQuestion(new string("Enter item to push: "));
	  if (!response) {
	    cout << "Error in reading item.  Aborting command.\n";
	  } else {
	    (*BS).push((*response));
	    delete response;
	  }
	}
	break;

      case 'p':
      case 'P':
	if (valid(BS)) {
	  try {
	    answer = (*BS).pop();
	    cout << "pop( ) returned " << answer << "\n";
	  } catch (BoundedStackEmptyException e) {
	    cout << "pop( ) threw BoundedStackEmptyException\n";
	  }

	}
	break;

      case 't':
      case 'T':
	if (valid(BS)) {
	  try {
	    answer = (*BS).top();
	    cout << "top( ) returned " << answer << "\n";
	  } catch (BoundedStackEmptyException e) {
	    cout << "top( ) threw BoundedStackEmptyException\n";
	  }

	}
	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;

  return(0);
}





