#include "MenuDriver.h"
#include <iostream>
#include <sstream>
#include <stdexcept>
/*
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include <istream>
#include <string>
*/

using namespace std;


MenuDriver::MenuDriver(int argc, const char* argv[])
  : MENU("(Q)  Quit."), isr(&cin), cinFail(false), limit(-1), pass(0)
{

  // choose between keyboard input or mock-keyboard file input
  if (argc>1) {
    inputfile.open(argv[1],ios::in);
    if (inputfile.is_open()) {
      isr = &inputfile;
    } 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?
  if (argc>2) {
    limit = atoi(argv[2]);
    if (limit < 1) {
      limit = -1;
      cout << "Second argument (" << argv[2] << ") ignored.\n\n";
    }
  }

}


bool MenuDriver::readYN(const string& prompt) {
  bool result = false;
  bool done = false;
  do {
    string s = read<string>(prompt);
    if ((s == "y") || (s == "Y") || (s == "yes") || (s == "Yes")) {
      result = true;
      done = true;
    } else if ((s == "n") || (s == "N") || (s == "no") || (s == "No")) {
      result = false;
      done = true;
    }
  } while (!done);

  return(result);
}



string MenuDriver::readLine(const string& prompt, bool forceNonEmpty, bool clearStream) {
  if (prompt.size())
    std::cout << prompt;

  if (clearStream) {
    //    isr->ignore(numeric_limits<int>::max(), '\n');   // problem is this may throw away partial line
    bool clearing = true;
    while (clearing) {
      char p = isr->peek();
      switch (p) {
      case ' ':
      case '\t':
	isr->get();
	break;

      case '\n':
	isr->get();
	// intentionally NO break here.  Want to end this loop when newline is cleared

      default:
	clearing = false;  // reached non-whitespace
      }
    }
  }

  std::string response = "";
  do {
    getline(*isr, response);
    if (isr != &std::cin)  // echo input
      std::cout << response << "\n";

    if (response.size() && response[response.size()-1]!='\n' && isr->eof())
      response += '\n';  // good enough
    else if (isr->eof() || (isr->bad())) {
      response = "";
      switchInput();
    }
  } while (forceNonEmpty && (response == "" || response == "\n"));

  return(response);
}


/**  Switches from file input to console input.
 *   This is typically called after receving an eof.
 *   @throws runtime_error when EOF was reached from cin.
 */
void MenuDriver::switchInput() {
  // called after reaching EOF on isr
  if (isr != &cin)
    isr = &cin;
  else if (isr->eof())
    throw runtime_error("unexpected end of input reached on console.");
  else if (isr->bad())
    throw runtime_error("critical failure on console input.");
}

int MenuDriver::run() {
  bool again = true;
  while (again && (limit < 0 || pass < limit))
    again = menuOnce();
  return 0;
}


bool MenuDriver::menuOnce() {
  pass++;
  if (isr == &cin)  // only print menu when working from console
    cout << endl << MENU << endl;  
  cout << "Command #" << pass << "> " << flush;
  string response = read<string>();
  return( handleChoice(response) );
}





