// tables.cpp   P. Conrad   for CISC181, Fall 2004
// Sample program using an array
// Number of guests at tables in a restaurant
// Tables are numbered 0 through NUM_TABLES - 1

// Things to notice in this program
//   (1) use of #define to set array size (NUM_TABLES) and
//       limit on table size
//   (2) structure of menu driven program
//   (3) use of "printWelcome();" and "printMenu();"
//       to factor out long series of "cout <<" from the main program
//   (4) use of "cin.getline(buffer, bufSize, "\n");
//   (5) use of guests = readFirstInteger(); instead of cin >> guests;
//   (6) techniques to use with arrays: initializing (manually), 
//       finding first occurence of a value (in this case, 0), 
//       setting a particular value, printing out entire array.
//   (7) use of the assert statement

#define NUM_TABLES 6 // number of tables
#define GUEST_MAX 4  // maximum guests per table

#include <iostream>
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
using std::getline;

#include <cassert> // for assert() function
#include <cstdlib> // for atoi

void printWelcome(void)
{
  cout << "Welcome to the restaurant table manager program. \n"
       << "\n"
       << "Because the restaurant owner loves C++, tables in\n" 
       << "are numbered from 0 through " << NUM_TABLES -1 << "\n"
       << "\n"
       << "Initially all tables are empty, and can hold up to four guests.\n"
       << endl;
  return;
}

void printMenu(void)
{
  cout << "\n"
       << "Enter R to reserve a table\n"
       << "      C to clear a table\n"
       << "      P to print status of all tables\n"
       << "      Q to quit" << endl;
  return;
}

char getFirstCharacter(void)
{
  // reads in an entire line of text up to the newline,
  // returns the first character read, and throws away the rest
  const int bufSize=80;
  char buffer[bufSize];
  cin.getline(buffer, bufSize, '\n');
  return buffer[0];
}

int readFirstInteger(void)
{
  // reads in an entire line of text up to the newline,
  // convert the first integer you find in the string
  //   from ascii to integer (atoi)
  // if conversion can't be performed, atoi returns 0

  const int bufSize=80;
  char buffer[bufSize];
  cin.getline(buffer, bufSize, '\n');
  return atoi(buffer);
}

// NOTE: This main is not the best style.  The problem is that it is too
// big.   A future version of this program will factor out the various
// cases of the switch statement to separate functions to simplify the
// code.

int main(void)
{
  int table[NUM_TABLES];
  int i; // declare it here so it can be used throughout

  printWelcome();

  // clear all tables
  for (int i=0; i<NUM_TABLES; i++)
    table[i]= 0; // could also have initalized in declaration
  // postcondition: all tables from 0 to NUM_TABLES - 1 have 0 guests
  
  char option;

  printMenu();
  cout << "Enter option: ";
  option = getFirstCharacter(); // instead of cin >> option
  while (option != 'Q' && option != 'q')
    {
      switch (option)
	{
	case 'R': case 'r':
	  // find first open table

	  for (i=0; i<NUM_TABLES && table[i]>0; i++)
	    ; // for loop has empty body;	  

	  // postcondition: if i < NUM_TABLES, table[i] is empty
	  // postcondition: if i == NUM_TABLES, all tables are full

	  if (i==NUM_TABLES)
	    cout << "Sorry, all tables are full";
	  else  
	    {
	      assert(i<NUM_TABLES); // assert precondition 
	      int guests;
	      cout << "Table " << i << " has space" << endl;
	      cout << "How many guests? (0 to cancel) :" ;
	      guests = readFirstInteger();
	      while (guests > GUEST_MAX || guests < 0)
		{
		  cout << "Enter a number between 0 and " << GUEST_MAX << endl;
		  cout << "How many guests? (0 to cancel) :" ;
		  guests = readFirstInteger();
		}
	      // reserve table
	      table[i] = guests;
	      // postcondition: table[i] is between 0 and 4.
	      assert(table[i] >= 0 && table[i] <= 4);
	    }

	  break;
	case 'C': case 'c':
	  
	  cout << "Which table do you wish to clear? ";
	  i = readFirstInteger();
	  if (i<0 || i>=NUM_TABLES)
	    {
	      cout << "Table number should be in range 0 to " << NUM_TABLES -1 
		   << endl;
	    }	   
	  else if (table[i] == 0)
	    {
	      cout << "That table is already clear \n" << endl;
	    }
	  else
	    {
	      cout << table[i] << " guests cleared from table " << i << endl;
	      table[i] = 0;
	    }
	  break;
	case 'P': case 'p':
	  for (i=0; i<NUM_TABLES; i++)
	    {
	      if (table[i] > 0)
		cout << "Table [" << i << "] has " << table[i] << " guests\n";
	      else
		cout << "Table [" << i << "] is clear \n";
	    }
	  break;
	default:
	  cout<< "Sorry, option " << option << " not understood.\n";
	  break;
	}

      printMenu();
      cout << "Enter option: ";
      option = getFirstCharacter();

    }
  
  cout << "Thanks.  Bye bye." << endl;
  return 0;
}


