/*
 *  For commentary on file, see lists.h
 */


#include "lists.h"

/*  Procedure definitions */

/*
 *  l_newlist (Create a new list)
 *
 *  This procedure will create a new list by setting a passed list pointer
 *  to the end of a list.
 *
 *  Input:  A List type
 *  Output:  List type = list end
 *           Returns a '1' for sucessful attempt
 */

List* l_newlist () {

   return(L_END);
}

/*
 *  l_first (Return the position of the first element)
 *
 *  By definiton, the name of the list _is_ the first posiotion, but if
 *  the programmer were to send a position within the list, this procedure
 *  will back up until it hits the head and it will return that position.
 *
 *  Input:  A List type or Position
 *  Output:  The Positon of the first element in the list or end of
 *           list if there are no elements in the list.
 */

L_POSITION l_first (List* l) {

   L_POSITION p;
   
   p = l;
   if (p == L_END){			/* if there are no elements... */
      return (L_END);
   }
      
   while (p->previous != L_END)		/* if there is a previous cell, */
      p = p->previous;			/* go to that cell */
   return (p);
}

/*
 *  l_last (Return the position of the last element)
 *
 *  This will check the next element in the passed cell and if it is not
 *  the "end" of the list it will jump to that cell and this will be
 *  repeated until the last element is found.
 *
 *  Input:  A List type or Position
 *  Output:  The Position of the last element in the list or end of
 *           list if there are no elements in the list
 */

L_POSITION l_last(List* l) {

   L_POSITION p;

   p = l;
   if (p==L_END)			/* if there are no elements... */
      return L_END;

   while (p->next != L_END)		/* if thre is a next cell, */
      p = p->next;			/* go to that cell */
   return p;
}

/*
 *  l_retrieve (Return the value of the object at a position)
 *
 *  This will simply return the value contained by the cell at the position
 *  passed to it.
 *
 *  Input:  A position (L_POSITION)
 *  Output:  the value of the OBJECT.  It will return L_BADDATA if it
 *           is an invalid position.
 */

L_OBJECT l_retrieve(L_POSITION p){

   if (p == L_END)		        /* if it's not a good position */
      return (L_BADDATA);

   else
      return (p->value);	        /* return the value at this point */
}

/*
 *  l_insert (Insert a value before passed position in a certain list)
 *
 *  OK, this is the procedure that does some work;  it takes a position and
 *  a value and with this information it will make a new cell previous
 *  to the passed position with the specified value.  If L_END is passed, then
 *  that item is added onto the end of the list.  If the first item is
 *  passed, then the new item is the first of the list.
 *
 *  Input:  A List (*list), a Position (L_POSITION), and a value (L_OBJECT)
 *  Output:  1 if successful (int)
 *           0 if failed (malloc or bad position)
 */

int l_insert (List** l, L_POSITION p, L_OBJECT o) {

   L_POSITION temp;			/* points to our new cell */
   L_POSITION eol;			/* to store the end of the list */

   if ((temp = malloc(sizeof (List))) == NULL) /* if malloc fails */
      return (0);

   if (*l == L_END){             	/* is this an empty list? */
      *l = temp;	       		/* Then let's tie off both */
      (*l)->previous = L_END;		/* ends. */
      (*l)->next = L_END; 
   }
   else if (p == L_END){		/* are we at the end */
      eol = (l_last(*l));		/* find the position of the last */
      eol->next = temp;                 /* last element points to new one */
      temp->previous = eol;
      temp->next = L_END;		/* make the new cell the end */
   }
   else if (p->previous == L_END){      /* are we making a new head? */
      temp->previous = L_END;		/* then make previous=end */
      p->previous = temp;
      temp->next = p;
      *l = temp;                	/* make the list point correctly */
   }
   else{
      temp->previous = p->previous;	/* otherwise, just link the */
      p->previous->next = temp;		/* cells together. */
      p->previous = temp;
      temp->next = p;
   }

   temp->value = o;			/* don't forget the value! */
   return(1);
}
      
   
/*
 *  l_delete (delete a cell at a certain position in a list)
 *
 *  This procedure will remove a cell from a list and de-allocate
 *  the space for it.
 *
 *  Input:  A List (*list), a Position (L_POSITION)
 *  Output:  1 if successful (int)
 *           0 if failed (nothing to delete or end of list)
 */

int l_delete (List** l, L_POSITION p){

   if (p == L_END) 			/* nothing to delete */
      return(0);

   if ((p->next == p->previous) && (p->previous == L_END)){  
      free (p);				/* We're erasing the list */
      *l = L_END;			/* make it the end of the list */
   }
   else if (p->previous == L_END){	/* Do we need to cut off the head? */
      *l = p->next;			/* next element is the head */
      p->next->previous = L_END;	/* tie off the end */
      free (p);				/* de-allocate the space */
   }
   else if (p->next == L_END){		/* it's the last element */
      p->previous->next = L_END;
      free (p);
   }
   else {				/* otherwise we need to tie a */
      p->next->previous = p->previous;  /* a couple of cells together */
      p->previous->next = p->next;
      free (p);
   }

   return (1);
}

/*
 *  l_next (return the position of the next cell)
 *
 *  This procedure will return the position of the next cell item
 *
 *  Input:  A position
 *  Output:  The next position
 */

L_POSITION l_next (L_POSITION p){

   if (p == L_END)		        /* Empty Pointer? */
      return (L_END);
   
   return (p->next);
}

/*
 *  l_prev (return the position of the previous cell)
 *
 *  This procedure will return the position of the previous cell
 *
 *  Input:  A position
 *  Output:  The previous position
 */

L_POSITION l_prev (L_POSITION p){

   if (p == L_END)			/* Empty Pointer? */
      return (L_END);
   return (p->previous);
}



