#include <string.h>
#include "list.h"
#include "helper.h"

void List_Create(List *list, size_t len) //just initialize everything
{
	if(!list)
	{
		return;
	}
	list->first = list->last = NULL;
	list->len = len;
}

void List_Destroy(List *list)
{
	Element *tmp, *tmp2;
	tmp=list->first;
	if(!tmp)
	{
		list->first = list->last = NULL;
		return ;
	}
	tmp2 = tmp->next; //tmp2 will stay one step ahead of tmp
	while(tmp)
	{
		delete_element(tmp);
		tmp=tmp2;
		if(tmp2)
		{
			tmp2 = tmp2->next;
		}
	}
	list->first = NULL;
	list->last = NULL;
}

void List_Insert(List *list, Pointer data, Position pos)
{
	Element *tmp, *n;
	n = new_element(data,list->len);
	tmp = list->first;
	if(!tmp) //the element becomes the first/last/only element
	{
		list->first = n;
		list->last = n;
		n = NULL;
		return ;
	}
	switch(pos) //-1/-2 will be used for FRONT/REAR, pos denotes the position
	{
		case FRONT:
		{
			tmp = list->first;
			n->next = tmp;
			tmp->prev = n;
			list->first = n;
			break;
		}
		case REAR:
		{
			tmp = list->last;
			tmp->next = n;
			n->prev = tmp;
			n->next = NULL;
			list->last = n;
			break;
		}
	}
	tmp = n = NULL;
}

void List_Remove(List *list, Index pos)
{
	Element *tmp=list->first, *prev, *next;
	Index i=pos;
	while(tmp && i) //either find the nth element or find NULL
	{
		tmp = tmp->next; //either tmp will reach the terminating NULL (0)
		i--; //or i will reach 0 
	}
	if(!tmp) //check for out of bounds
	{
		return;
	}
	prev = tmp->prev; //this will cause the previous element and the next
	next = tmp->next; //element to connecting, passing over the element
	if(prev)          //to be deleted
	{
		prev->next = next;
	}
	if(next)
	{
		next->prev = prev;
	}
	delete_element(tmp);
	if(tmp == list->first) //do some tidying up to make sure first and last
	{                      //are pointing at the right elements
		list->first = next;
	}
	if(tmp == list->last)
	{
		list->last = prev;
	}
	tmp = prev = next = NULL;
}

Pointer List_Position(List *list, Index pos)
{
	Element *tmp;
	Index i;
	Pointer p;
	tmp = list->first;
	i=pos;
	while(tmp && i) //same as before; OOB or current element
	{
		tmp = tmp->next;
		i--;
	}
	if(!tmp) //OOB
	{
		return NULL;
	}
	else
	{
		p = malloc(list->len);
		memcpy(p,tmp->data,list->len); //make copies of the current element's data
		return p;
	}
}

size_t List_Length(List *list)
{
	size_t i=0;
	Element *tmp;
	tmp = list->first;
	if(!tmp)
	{
		return 0;
	}
	while(tmp) //just count until you reach the terminating NULL
	{
		tmp=tmp->next;
		i++;
	}
	return i;
}
