/* Namqueue.c */
/* An example of using a queue. */

/* compiler directives */
#include<stdio.h>
#include<string.h>

/* constants for error conditions */
#define QUEUE_EMPTY 2
#define QUEUE_ERROR 1
#define NOERROR 0


/* global declarations */
  struct queue_node  /* node for item in queue */
    {
     char name[20];
     struct queue_node *next;
    };

  struct queue_node *head_ptr;  /* pointer to head of queue */
  struct queue_node *tail_ptr;  /* pointer to tail of queue */

/* function prototypes */
void handle_choice(int choice);
int add_customer(char *name);
void display_queue();
int next_customer(char *name);
void delete_queue();

/* main function */
int main()
{
  int choice;

  tail_ptr = NULL; /* Initialize pointers to */
  head_ptr = NULL; /* NULL since no queue exists. */
  do
   {
    printf("\n");
    printf("1 - Add a person to the queue\n");
    printf("2 - Take next customer\n");
    printf("3 - Display queue\n");
    printf("4 - Quit\n");
    printf("Enter choice: ");
    scanf(" %d", &choice);
    if(choice != 4)  /* If user does not want to quit, */
     {               /* do handle_choice. */
      handle_choice(choice);
     }
   } while(choice != 4); /* Loop until user chooses Quit. */
   if(head_ptr != NULL)
    {                 /* If queue isn't empty, */
     delete_queue();  /* delete the queue to free the memory. */
    }
   return 0;
} /* end of main function */

/* Function that handles the user's choice. */
void handle_choice(int choice)
{
  char name[20];
    switch(choice)
     {
      case 1:  /* User chose to add a customer to the queue. */
        printf("\nEnter customer's name: ");
        scanf(" %s", name);
        if(add_customer(name) == QUEUE_ERROR)
         {
           printf("\nQUEUE ERROR\n\n");
         }
        break;
      case 2:  /* User chose to get next customer from queue. */
        if(next_customer(name) == QUEUE_EMPTY)
         {
           printf("\nQUEUE EMPTY\n\n");
         }
        else
         {
           printf("\nThe next customer is %s.\n", name);
         }
        break;
      case 3:  /* User chose to display the queue. */
        if(head_ptr != NULL)
         {
           display_queue();
         }
        else
         {
           printf("\nQUEUE EMPTY\n\n");
         }
        break;
      default:
        printf("\nInvalid choice: Enter 1, 2, 3 or 4.\n\n");
        break;
     }
}

/* Function to add a customer to the queue. */
int add_customer(char *name)
{
  int status = NOERROR;

  struct queue_node *new_node;

  new_node = (struct queue_node *)malloc(sizeof(struct queue_node));  /* Allocate memory for the new node. */
  if(new_node == NULL)
   {                     /* If memory allocation problem, set error */
    status = QUEUE_ERROR; /* status and proceed to exit the function. */
   }
  else                   /* else copy data into the node and add to queue. */
   {
    strcpy(new_node->name, name);
    if(tail_ptr == NULL)
     {                        /* If queue is empty, make the new */
      new_node->next = NULL;  /* node the head and tail. */
      tail_ptr = new_node;
      head_ptr = new_node;
     }
    else
     {                           /* If queue is not empty, add the */
      tail_ptr->next = new_node; /* customer to the queue. */
      new_node->next = NULL;
      tail_ptr = new_node;
     }
   }
  return(status); /* return error status */
}

/* Function to display entire queue. */
void display_queue()
{
 struct queue_node *current_ptr;

 current_ptr = head_ptr;   /* Move current_ptr to head of queue. */

 printf("\n"); /* Display blank line before output. */
 if(current_ptr != NULL) /* If queue is not empty, start displaying. */
  {
   do
    {
     printf("%s\n", current_ptr->name);
     current_ptr = current_ptr->next; /* set current_ptr to point to next node */
    } while(current_ptr != NULL); /* loop until end of list */
  }
 else
  {
   printf("QUEUE EMPTY\n\n");
  }
}

/* Function that gets next customer from queue. */
int next_customer(char *name)
{
  struct queue_node *temp_ptr;
  int status = NOERROR;

  if(head_ptr != NULL)  /* If queue is not empty, get next customer. */
   {
    strcpy(name, head_ptr->name); /* Copy data out of head node. */
    temp_ptr = head_ptr->next;  /* Set temp pointer to node after head. */
    free( head_ptr);      /* Delete head node. */
    head_ptr = temp_ptr;   /* Move head_ptr to new head of queue. */
    if(head_ptr == NULL)
     {                  /* IMPORTANT!! If last customer is removed from */
      tail_ptr = NULL;  /* queue, set tail_ptr to NULL. */
     }
   }
  else                 /* If queue is empty, set error status. */
   {
    status = QUEUE_EMPTY;
   }
  return(status);
}

/* Function that frees the memory used by the queue. */
void delete_queue()
{
 char name[20];
 int status = NOERROR;

 do
  {
   status = next_customer(name);     /* Remove customers until */
  } while(status != QUEUE_EMPTY);    /* queue is empty. */
}
