/* File: list4.C

   Implementation of a simple linked list ADT in C++
*/

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

#include "list4.h"

/* Functions for this file only */
static void CrashOnNull(void *, char *) ;

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


/* ListNode member function implementations */


/* default constructor */
ListNode::ListNode() {
   item = NULL ;
   next = NULL ;
}


/* alternate constructor */
ListNode::ListNode(data x) {
   if (x != NULL) {
      item = strdup(x) ;
   } else {
      item = NULL ;
   }
   next = NULL ;
}


/* destructor */
ListNode::~ListNode() {
   if (item != NULL) free(item) ;
}



/* List member function implementations */


/* default constructor */
List::List() {
   count = 0 ;   
   last = &header ;
}


/* destructor */
List::~List() {
   ListNode *current, *temp ;

   current = header.next ;

   while (current != NULL) {
      temp = current ;
      current = current->next ;
      delete temp ;
   }
}


/* Add item to the end of the list */
void List::Append(data x) {
   ListNode *ptr ;

   ptr = new ListNode(x) ;
   last->next = ptr ;
   last = ptr ;   
   count++ ;
}


/* Add item to the beginning of the list */
void List::Prepend(data x) {
   ListNode *ptr ;

   ptr = new ListNode(x) ;
   ptr->next = header.next ;
   header.next = ptr ;
   count++ ;

   if (ptr->next == NULL) last = ptr ;
}


/* Remove node at given position */
void List::Delete(position pos) {
   ListNode *temp ;

   /* Sanity check */
   if (pos == NULL || pos->next == NULL) return ;

   temp = pos->next ;
   pos->next = pos->next->next ;
   delete temp ;
   count-- ;

   /* Check if we deleted the last node */
   if (pos->next == NULL) last = pos ; 
}


/* Item on the list? 0=No 1=Yes */
int List::IsMember(data x) {
   ListNode *current ;

   current = header.next ;

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

   return 0 ;
}


/* Add list to the end of this one, second list destroyed */
void List::Concatenate(List *L2) {
   
   count += L2->count ;
   last->next = L2->header.next ;
   if (last->next != NULL) {
      last = L2->last ;
   }

   /* isolate L2 from old data */
   L2->header.next = NULL ;
   L2->last = &L2->header ;
   L2->count = 0 ;

   delete L2 ;
}


/* Return copy of this list */
List *List::Duplicate() {
   List *NewL ;
   ListNode *copyto, *copyfrom ;

   NewL = new List ;
   CrashOnNull(NewL, "could not create new list") ;
   NewL->count = count ;

   copyto = &NewL->header ;
   copyfrom = header.next ;

   while(copyfrom != NULL) {
      copyto->next = new ListNode(copyfrom->item) ;      
      copyto = copyto->next ;
      copyfrom = copyfrom->next ;
   }

   NewL->last = copyto ;
   return NewL ;
}


/* Print the contents of this list */
void List::Print() {
   ListNode *current ;

   current = header.next ;

   if (current == NULL) {
      printf("<>\n") ;
      return ;
   }

   printf("<") ;
   while (1) {
      printf("%s", current->item) ;
      current = current->next ; 

      if (current == NULL) break ;

      printf(", ") ;
   }
   printf(">\n") ;
}


/* Return number of items in this list */
int List::Count() {
   return count ;
}


/* Return a copy of the first item on the list */
data List::FirstItem() {
   data x ;   

   if (count == 0) return NULL ;

   x = strdup(header.next->item) ;
   CrashOnNull(x, "could not copy data item") ;
   return x ;
}


/* Return a copy of the last item on the list  */
data List::LastItem() {
   data x ;

   x = strdup(last->item) ;
   CrashOnNull(x, "could not copy data item") ;
   return x ;
}


/* Return copy of item at given position */
data List::ItemAt(position pos) {
   data x ;

   if (pos == NULL || pos->next == NULL) {
      return NULL ;
   }

   x = strdup(pos->next->item) ;
   CrashOnNull(x, "could not copy data item") ;
   return x ;
}


/* Position of the first item */
position List::FirstPos() {
   return &header ;
}


/* Position after the given one */
position List::NextPos(position pos) {
   if (pos == NULL) return NULL ;
       
   return pos->next ;
}


/* Position of data on list. return NULL if no such node found.*/
position List::Locate(data x) {
   ListNode *prev ;

   prev = &header ;

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

   return NULL ;
}
