#include "linkedlistint.h"
#include <string.h>
void SetPosition(Position,List *);
ListNode *MakeListNode(ListEntry);
void CopyEntry(ListEntry *, ListEntry);

void CopyEntry(ListEntry *dest, ListEntry src) {
   strcpy(*dest, src);
}

ListNode *MakeListNode(ListEntry x) {
   ListNode *p = (ListNode *) malloc(sizeof(ListNode));

   if (p != NULL) {
      CopyEntry(&(p->entry),x);
      p->next = NULL;
      p->previous = NULL;
   }
   else
      Error("No space for additional node available");
   return p;
}

void SetPosition(Position p, List *thelist) {
   if (p < 0 || p >= thelist->count)
      Error("Bad position");
   else if (thelist->currentpos < p) {
      while (thelist->currentpos != p) {
         thelist->current = thelist->current->next;
         (thelist->currentpos)++;
      }
   }
   else if (thelist->currentpos > p) {
      while (thelist->currentpos != p) {
         thelist->current = thelist->current->previous;
         (thelist->currentpos)--;
      }
   }
}

void InsertList(Position p, ListEntry x, List *thelist) {
   ListNode *newnode, *following;

   if (p < 0 || p > thelist->count)
      Error("Bad position for inserting");
   else {
      newnode = MakeListNode(x);
      if (p == 0) { /* insert at beginning of list */
         newnode->previous = NULL;
         if (thelist->count == 0) /* thelist was empty */
            newnode->next = NULL;
         else {
            SetPosition(0,thelist);
            newnode->next = thelist->current;
            thelist->current->previous = newnode;
         }
      }
      else { /* later in list */
         SetPosition(p-1,thelist);
         following = thelist->current->next;
         /* insert between current and following */
         newnode->next = following;
         newnode->previous = thelist->current;
         thelist->current->next = newnode;
         if (following != NULL)
            following->previous = newnode;
      }
      thelist->current = newnode;
      thelist->currentpos = p;
      (thelist->count)++;
   }
}

void CreateList(List *thelist) {
   thelist->count = 0;
}

int ListSize(const List *thelist) {
   return thelist->count;
}

Boolean ListEmpty(const List *thelist) {
   return (thelist->count == 0);
}

void RetrieveList(Position p, ListEntry *x, List *thelist) {
   if (p < 0 || p >= thelist->count || thelist->count == 0)
      Error("Invalid position for retrieving");
   else {
      SetPosition(p,thelist);
      CopyEntry(x, thelist->current->entry);
   }
}

Boolean ListFull(const List *thelist) {
   return (FALSE);
}

void ClearList(List *thelist) {
   ListEntry x;
   while (ListSize(thelist) > 0)
      DeleteList(0,&x,thelist);
}

void ReplaceList(Position p, ListEntry x, List *thelist) {
   if (p < 0 || p >= thelist->count)
      Error("Attempt to replace a position not in the list");
   else {
      SetPosition(p,thelist);
      CopyEntry(&(thelist->current->entry),x);
   }
}

void DeleteList(Position p, ListEntry *x, List *thelist) {
   ListNode *rid;

   if (p < 0 || p >= thelist->count)
      Error("Attempt to delete a position not in the list");
   else {
      SetPosition(p,thelist);
      CopyEntry(x, thelist->current->entry);
      rid = thelist->current;
      if (p == 0) { /* deleting the first item in the list */
         if (rid->next != NULL) {
            rid->next->previous = NULL;
         }
         thelist->current = rid->next;
      }
      else {
         if (rid->next != NULL) {
            rid->next->previous = rid->previous;
         }
         rid->previous->next = rid->next;
         thelist->current = rid->previous;
         thelist->currentpos = p-1;         
      }
      free(rid);
      (thelist->count)--;
   }
}

void TraverseList(List *thelist, void (*Visit)(ListEntry)) {
   int i;
   ListEntry currentry;
   for (i = 0; i < thelist->count; i++) {
      RetrieveList(i,&currentry,thelist);
      (*Visit)(currentry);
   }
}
   
void AddList (ListEntry x, List *thelist) {
   InsertList(ListSize(thelist), x, thelist);
}

void CopyList(List *dest, List *source) {
   int i;
   ListEntry x;

   ClearList(dest);

   for (i = 0; i < ListSize(source);i++) {
      RetrieveList(i,&x,source);
      AddList(x,dest);
   }
}

