/************************* HOSPITAL3.CPP **************************************
* Example showing a linked list                                    1998-09-31 *
*                                                                   Agner Fog *
* A hospital's waiting-lists                                                  *
* --------------------------                                                  *
*                                                                             *
* The hospital in Software City has three departments: heart clinic, lung     *
* clinic, and plastic surgery. The head nurse keeps three lists of patients   *
* waiting for an operation, one for each department. Each new patient         *
* normally comes last in the queue, but critically ill patients and patients  *
* who bribe the chief surgeon come first in the queue. Some patients die      *
* while waiting for an operation. This program keeps track of the three       *
* patient queues.                                                             *
*                                                                             *
* A structure called patient holds all information for one patient.           *
* A class called queue encapsulates a patient queue for one department,       *
* implemented as a linked list. Patient records are created dynamically.      *
*                                                                             *
******************************************************************************/
#include <iostream.h>   
#include <conio.h>
#include <string.h>
#include <stdlib.h>

// define maximum number of patients in a queue
#define MAXPATIENTS 100

// define structure for patient data
struct patient {
   patient * next;
   char FirstName[50];
   char LastName[50];
   char ID[20];
};


// define class for queue
class queue {
   public:
   queue (void);
   ~queue (void);
   int AddPatientAtEnd (patient * p);
   int AddPatientAtBeginning (patient * p);
   patient * GetNextPatient (void);
   patient * RemoveDeadPatient (patient * p);
   void OutputList (void);
   char DepartmentName[50];
   private:
   patient * List[MAXPATIENTS];
   patient * first, * last;
};


// declare member functions for queue

queue::queue () {
   // constructor
   first = last = NULL;}


queue::~queue () {
   // destructor
   patient * p1, * p2;
   for (p1=first; p1; ) {
      p2 = p1;
      p1 = p1->next;
      delete p2;}}


int queue::AddPatientAtEnd (patient * p) {
   // adds a normal patient to the end of the queue.
   // returns 1 if successful, 0 if queue is full.
   if (p == NULL) {
      // memory is full
      return 0;}
   // put in new patient
   if (first) {
      last->next = p;  last = p;}
   else {
      // queue is empty
      first = last = p;}
   p->next = NULL;
   return 1;}


int queue::AddPatientAtBeginning (patient * p) {
   // adds a critically ill patient to the beginning of the queue.
   // returns 1 if successful, 0 if queue is full.
   if (p == NULL) {
      // memory is full
      return 0;}
   // put in new patient
   if (first) {
      p->next = first;
      first = p;}
   else {
      // queue is empty
      first = last = p;
      p->next = NULL;}
   return 1;}


patient * queue::GetNextPatient (void) {
   // gets the patient that is first in the queue.
   // returns NULL if queue is empty
   patient * p;
   if (first) {
      p = first;
      first = first->next;}
   else {
      // queue is empty
      p = NULL;}
   return p;}


patient * queue::RemoveDeadPatient (patient * p) {
   // removes a patient from queue.
   // returns patient if found or NULL if not found
   patient * p1, * p2 = NULL;
   // search for patient
   for (p1=first; p1; p1 = p1->next) {
      if (stricmp(p1->ID, p->ID) == 0) {
         // patient found in queue
         // remove from queue
         if (p1 == first) {
            // adjust first
            first = first->next;}
         if (p1 == last) {
            // adjust last
            last = p2;}
         if (p2) {
            // adjust pointer in previous record
            p2->next = p1->next;}
         return p1;}
      // remember previous record
      p2 = p1;}
   // not found
   return NULL;}


void queue::OutputList (void) {
   // lists entire queue on screen
   patient * temp;
   if (first) {
      for (temp=first; temp; temp = temp->next) {
         cout << "\n" << temp->FirstName;
         cout << " " << temp->LastName;
         cout << " " << temp->ID;}}
   else {
     // queue empty
     cout << "\n\nQueue is empty";}}


// declare functions used by main:

patient * InputPatient (void) {
   // this function asks user for patient data.
   // create new patient record
   patient * p = new patient;
   // enter data into record
   cout << "\n\nPlease enter data for new patient\nFirst name: ";
   cin.getline(p->FirstName, sizeof(p->FirstName));
   cout << "\nLast name: ";
   cin.getline(p->LastName, sizeof(p->LastName));
   cout << "\nSocial security number: ";
   cin.getline(p->ID, sizeof(p->ID));
   // check if data valid
   if (p->FirstName[0]==0 || p->LastName[0]==0 || p->ID[0]==0) {
      // rejected
      delete p;  p = NULL;
      cout << "\n\nError: Data not valid. Operation cancelled.";
      getch();}
   return p;}


void OutputPatient (patient * p) {
   // this function outputs patient data to the screen
   if (p == NULL) {
      cout << "\nNo patient";
      return;}
   cout << "\n\nPatient data:";
   cout << "\n\nFirst name: " << p->FirstName;
   cout << "\n\nLast name: " << p->LastName;
   cout << "\n\nSocial security number: " << p->ID;}


int ReadNumber() {
   // this function reads an integer number from the keyboard.
   // it is used because input with cin >> doesn't work properly!
   char buffer[20];
   cin.getline(buffer, sizeof(buffer));
   return atoi(buffer);}       


void DepartmentMenu (queue * q) {
   // this function defines the user interface with menu for one department
   int choise = 0, success;  patient * p, * p1;
   while (choise != 6) {
      // clear screen
      clrscr();
      // print menu
      cout << "\n\n\nWelcome to department: " << q->DepartmentName;
      cout << "\n\nPlease enter your choise:";
      cout << "\n\n1:  Add normal patient";
      cout << "\n2:  Add critically ill patient";
      cout << "\n3:  Take out patient for operation";
      cout << "\n4:  Remove dead patient from queue";
      cout << "\n5:  List queue";
      cout << "\n6:  Change department or exit\n";
      // get user choise
      choise = ReadNumber();
      // do indicated action
      switch (choise) {
      case 1:   // Add normal patient
         p = InputPatient();
         if (p) {
            success = q->AddPatientAtEnd(p);
            clrscr();
            if (success) {
               cout << "\nPatient added:\n\n";
               OutputPatient(p);}
            else {
               // error
               cout << "\n\nError: The queue is full. Cannot add patient:";
               OutputPatient(p);
               delete p;}
            cout << "\n\nPress any key";
            getch();}
         break;

      case 2:   // Add critically ill patient
         p = InputPatient();
         if (p) {
            success = q->AddPatientAtBeginning(p);
            clrscr();
            if (success) {
               cout << "\nPatient added:\n\n";
               OutputPatient(p);}
            else {
               // error
               cout << "\n\nError: The queue is full. Cannot add patient:";
               OutputPatient(p);
               delete p;}
            cout << "\n\nPress any key";
            getch();}
         break;

      case 3:   // Take out patient for operation
         p = q->GetNextPatient();
         clrscr();
         if (p) {
            cout << "\nPatient to operate:\n\n";
            OutputPatient(p);
            // delete patient record
            delete p;}
         else {
            cout << "\nThere is no patient to operate.";}
         cout << "\n\nPress any key";
         getch();
         break;

      case 4:   // Remove dead patient from queue
         p = InputPatient();
         if (p) {
            p1 = q->RemoveDeadPatient(p);
            clrscr();
            if (p1) {
               cout << "\nPatient removed:\n\n";
               delete p;}
            else {
               // error
               cout << "\n\nError: Cannot find patient:\n\n";
               p1 = p;}
            OutputPatient(p1);  delete p1;
            cout << "\n\nPress any key";
            getch();}
         break;

      case 5:   // List queue
         clrscr();
         q->OutputList();
         cout << "\n\nPress any key";
         getch();  break;
         }}}


// main function defining queues and main menu
void main () {
   int i, MenuChoise = 0;
   // define three queues
   queue departments[3];
   // set department names
   strcpy (departments[0].DepartmentName, "Heart clinic");
   strcpy (departments[1].DepartmentName, "Lung clinic");
   strcpy (departments[2].DepartmentName, "Plastic surgery");

   while (MenuChoise != 4) {
      // clear screen
      clrscr();
      // print menu
      cout << "\n\n\nWelcome to Software City Hospital";
      cout << "\n\nPlease enter your choise:\n";
      for (i = 0; i < 3; i++) {
         // write menu item for department i
         cout << "\n" << (i+1) << ":  " << departments[i].DepartmentName;}
      cout << "\n4:  Exit\n";
      // get user choise     
      MenuChoise = ReadNumber();
      // is it a department name?
      if (MenuChoise >= 1 && MenuChoise <= 3) {
         // call submenu for department
         // (using pointer arithmetics here:)
         DepartmentMenu (departments + (MenuChoise-1));}}}





