/* File: list2.c

   Implementation of an ordered linked list ADT
*/

#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "list2.h"


/* Private Function Prototypes */

static void CrashOnNull(void *, char *) ;
static node *NewNode(char *) ;
static void FreeNode(node *ptr) ;


/* Private Function Implementations */

/* Exit if ptr is NULL. */
static void CrashOnNull(void *ptr, char *mesg) {
   if (ptr == NULL) {
      fprintf(stderr, "%s\n", mesg) ;
      exit(1) ;
   }
}


/* Make a new node with given item and next field set to NULL */
static node *NewNode(char *item) {
   node *new ;

   new = (node *) malloc (sizeof(node)) ;
   CrashOnNull(new, "cannot make new node") ;

   if (item == NULL) item = "" ;
   new->item = strdup(item) ;
   CrashOnNull(new->item, "cannot duplicate string") ;

   new->next = NULL ;
   return new ;
}


/* Free memory allocated to the node */
static void FreeNode(node *ptr) {
   
   if (ptr->item != NULL) free(ptr->item) ;
   free(ptr) ;
}



/* Add an item to the sorted list */
void AddItem (list L, char *item) {
   node *prev, *new ;   

   new = NewNode(item) ;
   
   prev = &L->header ;
   while (prev->next != NULL && strcmp(prev->next->item, item) < 0) {
      prev = prev->next ;
   }

   new->next = prev->next ;
   prev->next = new ;
   L->count++ ;

   if (new->next == NULL) L->last = new ;
}


/* Does item with key appear on the ordered list? 0=No 1=Yes */
int IsMember2(list L, char *key) {
   node *current ;
   int r ;

   current = L->header.next ;

   while(current != NULL) {
      r = strcmp(current->item, key) ;
      if (r == 0) return 1 ;
      if (r > 0) return 0 ;
      current = current->next ;
   }
   return 0 ;
}


/* Return the position in the ordered list of an item with key or
   NULL if no such item.

   The position is a pointer to the node prior to the item with
   the key.
*/
node *Search (list L, char *key) {
   node *prev ;
   int r ;

   prev = &L->header ;

   while(prev->next != NULL) {
      r = strcmp(prev->next->item, key) ; 
      if (r == 0) return prev ;
      if (r > 0) return NULL ;
      prev = prev->next ;
   }

   return NULL ;
}



/* Merge list L2 into list L1, removing duplicates.  L2 is destroyed. */
void MergeList(list L1, list L2) {
   node *prev1, *current2, *temp ;
   int r ;

   prev1 = &L1->header ;
   current2 = L2->header.next ;
   L1->count += L2->count ;

   while (prev1->next != NULL && current2 != NULL) {
      r = strcmp(prev1->next->item, current2->item) ;
      if (r > 0) {

	 /* Found right place to insert current L2 item */
	 temp = current2 ;
	 current2 = current2->next ;
	 temp->next = prev1->next ;
	 prev1->next = temp ;
	 prev1 = temp ;

      } else if (r < 0) {

	 /* next L1 item smaller than current L2 item */
	 prev1 = prev1->next ; 

      } else {

         /* found duplicate L1 and L2 item */
	 temp = current2 ;
	 current2 = current2->next ;
         FreeNode(temp) ;
	 L1->count-- ;
      }
   }

   /* Add remaining items from L2 if any */
   if (prev1->next == NULL && current2 != NULL) {
      prev1->next = current2 ;
      L1->last = L2->last ;
   }

   free(L2) ;
}

