//  File: list6.C
//
//  A C++ implementation of linked-lists, using C++ reference parameters
//  and other C++ features

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

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


// alternate constructor
ListNode::ListNode(const ListItem& x) {
   x.copyto(item) ;     // item passed by reference
   next = NULL ;
}


// destructor
ListNode::~ListNode() {
   // do nothing, ListItem destructor was called
}


//======================================================================
// List member function implementations


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


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

   // Iterate through the list, deleting each ListNode
   current = header.next ;
   while (current != NULL) {
      temp = current ;
      current = current->next ;
      delete temp ;
   }
}


// Add item to the end of the list
void List::Append(const ListItem& 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(const ListItem& 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(const ListItem& x) {
   ListNode *current ;

   current = header.next ;

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

   return 0 ;
}


// Add list to the end of this one, second list becomes empty
void List::Concatenate(List *L2) {

   if (this == L2) {
      fprintf(stderr, "Cannot concatenate list with itself!\n") ;
      exit(1) ;
   }

   count += L2->count ;
   last->next = L2->header.next ;
   if (last->next != NULL) {
      last = L2->last ;
   }

   // make L2 an empty list
   L2->header.next = NULL ;
   L2->last = &L2->header ;
   L2->count = 0 ;
}



// 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) {

      temp = new ListNode(copyfrom->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->item.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
ListItem *List::FirstItem() {

   if (count == 0) return NULL ;

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


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

   if (count==0) return NULL ;

   return last->item.copy() ;
}


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

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

   return pos->next->item.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(const ListItem &x) {
   ListNode *prev ;

   prev = &header ;

   while(prev->next != NULL) {
      if ( prev->next->item.compare(x) == 0)  return prev ;

      prev = prev->next ;
   }

   return NULL ;
}
