/* File: list5.C

   A more modular implementation of a simple linked list ADT in C++
*/

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

#include "list5.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() {
   itemp = NULL ;
   next = NULL ;
}


/* alternate constructor */
ListNode::ListNode(data x) {
   itemp = new ListItem(x) ;
   CrashOnNull(itemp, "could not make new ListItem") ;
   next = NULL ;
}


/* destructor */
ListNode::~ListNode() {
   delete itemp ;
}



/* 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) ;
   CrashOnNull(ptr, "could not make new ListNode") ;

   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) ;
   CrashOnNull(ptr, "could not make new ListNode") ;

   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 ( current->itemp->compare(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, *temp ;

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

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

   while(copyfrom != NULL) {

/* old version:
      temp = new ListNode(copyfrom->itemp->copy()) ;      
*/
      temp = new ListNode(copyfrom->itemp->item) ;      

      CrashOnNull(temp, "could not create new list") ;
      copyto->next = temp ;

      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) {
      current->itemp->print() ;
      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() {

   if (count == 0) return NULL ;

   return header.next->itemp->copy() ;
}


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

   return last->itemp->copy() ;
}


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

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

   return pos->next->itemp->copy() ;
}


/* 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 ( prev->next->itemp->compare(x) == 0)  return prev ;
      
      prev = prev->next ;
   }

   return NULL ;
}
