// Project 2, step 1  p2s1.cpp
// P. Conrad, Spring 2004

#include <iostream>

using std::endl;
using std::cout;
using std::cin;
using std::cerr;
using std::flush;

#include <iomanip>
using std::setw;

const int inputLineLen = 1024; // something like max input buffer size

#include <cstdlib> // for atoi

#include <cstring> // for strncpy


struct Birthday_S
{
  char *name;
  int month;
  int day;
  Birthday_S *next;
};

#include <new> // because somewhere I read this is a good idea

char promptForOption();

// function prototypes

void addBirthdayToList(Birthday_S **headPtr, Birthday_S **tailPtr);
void deleteBirthdayFromList(Birthday_S **headPtr, Birthday_S **tailPtr);
void insertBirthdayAtTail(Birthday_S *p, Birthday_S **headPtr, Birthday_S **tailPtr);
void printSummary(Birthday_S *head);
void quitProgram();
void listBirthdays(Birthday_S *head);
void updateBirthdayInfo(Birthday_S *head);
void printErrorMessage();
void printBirthdayHeaders();
void printBirthday(Birthday_S *p);
void findBirthday(Birthday_S *p);
void printMenu();


int main(void)
{
  Birthday_S *head;
  Birthday_S *tail;
  
  // initialize empty list

  head = tail = NULL;
  
  char option;

  while (1) // infinite loop; get out via exit(-1) inside quitProgram();
    {
      option = promptForOption();

      switch (option)
	{
	case 'a':
	  addBirthdayToList(&head, &tail);
	  break;
	case 'd':
	  deleteBirthdayFromList(&head, &tail);
	  break;
	case 'f':
	  findBirthday(head);
	  break;
	case 's':
	  printSummary(head);
	  break;
	case 'q':
	  quitProgram();
	  break;
	case 'l':
	  listBirthdays(head);
	  break;
	case 'u':
	  updateBirthdayInfo(head);
	  break;
	default:
	  printErrorMessage();
	}
    }
  return 0;
}

void printMenu()
{
  cout << endl
       << " Main Menu: " << endl
       << "    a: add team to list " << endl
       << "    d: delete team " << endl
       << "    f: find team " << endl
       << "    l: list teams " << endl
       << "    q: quit program   " << endl
       << "    s: summarize list  " << endl
       << "    u: update team info  " << endl
       << endl;
}

char promptForOption(void)
{
  char option;
  printMenu();
  cout << "Enter option > " << flush;
  cin >> option;
  cin.ignore(80,'\n'); // ignore all remaining characters on the line
  return option;
}


void findBirthday(Birthday_S *head)
{
  char key[shortStringLen]; // key is the team we are searching for

  cout << "Enter domain name to search for > " << flush;
  cin.getline(key,shortStringLen,'\n');
  
  Birthday_S *p;

  int headersPrinted = 0;

  for (p=head; p!=NULL ; p=p->next)
    {
      if (strcmp(p->domainName,key)==0) // key matches
	{
	  if (!headersPrinted)
	    {
	      printBirthdayHeaders();
	      headersPrinted = 1;
	    }
	  printBirthday(p);      
	} // if key matches
    } // end for   
  
}


void deleteBirthdayFromList(Birthday_S **headPtr, Birthday_S **tailPtr)
{
  char key[shortStringLen]; // key is the team we are searching for

  cout << "Enter domain name to search for > " << flush;
  cin.getline(key,shortStringLen,'\n');
  
  Birthday_S *p;
  Birthday_S *trailp;

  int headersPrinted = 0;

  // trailp should "trail" the pointer p, and be the
  // pointer to the element _before_ the matching one

  trailp = NULL;

  for (p=(*headPtr); p!=NULL ; trailp = p, p=p->next)
    {
      if (strcmp(p->domainName,key)==0) // key matches
	{
	  cout << "Deleting this element: " << endl;
	  printBirthdayHeaders();
	  printBirthday(p);      

	  if (trailp == NULL) 	      // we are deleting the head element
	    (*headPtr) = p->next;
	  else
	    trailp->next = p->next; // make the prev element point past p

	  if (p==(*tailPtr)) // we are deleting the tail  
	    (*tailPtr) = trailp; // update the tail

	  break;
	} // if key matches
      
    } // end for   
  
}

void addBirthdayToList(Birthday_S **headPtr, Birthday_S **tailPtr)
{
  Birthday_S *p;

  p = new Birthday_S;
  cout << "Adding a new node: " << endl;

  cout << " Enter domain name > " << flush;
  cin.getline(p->domainName,shortStringLen,'\n');
  p->domainName[shortStringLen-1] = '\0';

  cout << " Enter full school name > " << flush;
  cin.getline(p->fullName,longStringLen,'\n');
  p->fullName[longStringLen-1] = '\0';

  cout << " Enter mascot > " << flush;
  cin.getline(p->mascot,longStringLen,'\n');
  p->mascot[longStringLen-1] = '\0';

  cout << " Enter city > " << flush;
  cin.getline(p->city,shortStringLen,'\n');
  p->city[shortStringLen-1] = '\0';

  char stateString[shortStringLen];
  cout << " Enter state > " << flush;
  cin.getline(stateString,shortStringLen,'\n');
  strncpy(p->state,stateString,3);
  p->state[2]= '\0';

  char foundingYearString[shortStringLen];
  cout << " Enter founding year> " << flush;
  cin.getline(foundingYearString,shortStringLen,'\n');
  p->foundingYear=atoi(foundingYearString);
  
  p->next = NULL;
  
  insertBirthdayAtTail(p, headPtr, tailPtr);

}

void updateBirthdayInfo(Birthday_S *head)
{
  char key[shortStringLen]; // key is the team we are searching for

  cout << "Enter domain name to search for > " << flush;
  cin.getline(key,shortStringLen,'\n');
  
  Birthday_S *p;

  int headersPrinted = 0;


  for (p=head; p!=NULL ; p=p->next)
    {
      if (strcmp(p->domainName,key)==0) // key matches
	{
	  char shortString[shortStringLen];
	  char longString[longStringLen];

	  cout << "Enter a blank line to keep old value for any item. "<< endl;
	  cout << endl;

	  cout << " Current value of domain name > " << p->domainName << endl;
	  cout << " New value > " << flush;
	  cin.getline(shortString,shortStringLen,'\n');
	  shortString[shortStringLen-1] = '\0';
	  if (strcmp(shortString,"")!=0)
	    {
	      strncpy(p->domainName,shortString,shortStringLen);
	    }

	  cout << " Current value of full name > " << p->fullName << endl;
	  cout << " New value > " << flush;
	  cin.getline(longString,longStringLen,'\n');
	  longString[longStringLen-1] = '\0';
	  if (strcmp(longString,"")!=0)
	    {
	      strncpy(p->fullName,longString,longStringLen);
	    }

	  cout << " Current value of mascot > " << p->mascot << endl;
	  cout << " New value > " << flush;
	  cin.getline(longString,longStringLen,'\n');
	  longString[longStringLen-1] = '\0';
	  if (strcmp(longString,"")!=0)
	    {
	      strncpy(p->mascot,longString,longStringLen);
	    }
	  
	  cout << " Current value of city > " << p->city << endl;
	  cout << " New value > " << flush;
	  cin.getline(shortString,shortStringLen,'\n');
	  shortString[shortStringLen-1] = '\0';
	  if (strcmp(shortString,"")!=0)
	    {
	      strncpy(p->city,shortString,shortStringLen);
	    }

	  cout << " Current value of state > " << p->state << endl;
	  cout << " New value > " << flush;
	  cin.getline(shortString,3,'\n');
	  shortString[2]='\0';
	  if (strcmp(shortString,"")!=0)
	    {
	      strncpy(p->state,shortString,3);
	    }

	  cout << " Current value of foundingYear > " << p->foundingYear 
	       << endl;
	  cout << " New value > " << flush;
	  cin.getline(shortString,shortStringLen,'\n');
	  shortString[shortStringLen-1] = '\0';
	  if (strcmp(shortString,"")!=0)
	    {
	      p->foundingYear = atoi(shortString);
	    }

	  cout << "Here are the updated values: " << endl;

	  printBirthday(p);      
	} // if key matches
    } // end for   
  
}



void insertBirthdayAtTail(Birthday_S *p, Birthday_S **headPtr, Birthday_S **tailPtr)
{
  if ((*headPtr)==NULL) // if this is the first element in list
    {
      (*headPtr)=p;
    }
  else // link last element in list to this new element
    {
      (*tailPtr)->next = p;
    }
  (*tailPtr) = p; // make p the new tail
}

void printSummary(Birthday_S *head)
{
  int count=0;
  Birthday_S *p;
  for (p=head; p; p=p->next)
    count++;

  cout << "There are " << count << " teams in the list. " << endl;

}

void quitProgram()
{
  cout << "Thanks for using this program " << endl;
  exit(-1);
}

void listBirthdays(Birthday_S *head)
{
  Birthday_S *p;
  printBirthdayHeaders();
  for (p=head; p; p=p->next)
    printBirthday(p);

}

void printErrorMessage()
{
  cout << "That option was not understood; please try again" << endl;
}


void printBirthdayHeaders()
{

  cout << setw(12) << "Domain"
       << setw(25) << "Full Name"
       << setw(15) << "Mascot"
       << setw(15) << "City"
       << setw(3)  << "St"
       << setw(5 ) << "Year"  << endl;

  cout << setw(12) << "======"
       << setw(25) << "========="
       << setw(15) << "======"
       << setw(15) << "===="
       << setw(3)  << "=="
       << setw(5 ) << "===="  << endl;

}


void printBirthday(Birthday_S *p)
{
  cout << setw(12) << p->domainName
       << setw(25) << p->fullName
       << setw(15) << p->mascot
       << setw(15) << p->city
       << setw(3)  << p->state
       << setw(5 ) << p->foundingYear << endl;
}

