#include "utility.h"
#include <cstdlib>

#include "llnode.h"



template <class List_entry>
class LinkedList {
public:
//  Add specifications for methods of the list ADT.
//  Add methods to replace compiler generated defaults.
	LinkedList();
	//~LinkedList();
	//LinkedList(const LinkedList<List_entry>&copy);
	//void operator=(const LinkedList<List_entry> &copy);


	Error_code insert(int position, const List_entry &x);
	Error_code remove(int position);
	void traverse(void (*visit)(List_entry &));
	//void print(List_entry &x);
	void printList();

protected:
//  Data members for the doubly-linked list implementation follow:
   int count;
   Node <List_entry> *head;
   Node <List_entry> *set_position(int position) const;


};

template <class List_entry>
Node<List_entry> *LinkedList<List_entry>::set_position(int position) const
/*
Pre:  position is a valid position in the List: 0 <= position < count.
Post: The current Node pointer references the Node at position.
*/
{
   Node <List_entry> *q = head;
   for(int i = 0; i < position; i++)
	   q = q->next;
	   return q;
}


template <class List_entry>
LinkedList<List_entry>::LinkedList()
{
count = 0;

}



template <class List_entry>
Error_code LinkedList<List_entry>::insert(int position, const List_entry &x)
/*
Post: If the List is not full and 0 <= position <= n,
      where n is the number of entries in the List, the function succeeds:
      Any entry formerly at position and all later entries have their
      position numbers increased by 1 and x is inserted at position of the List.
      Else: the function fails with a diagnostic error code.
*/
{
   
	if (position < 0 || position > count) 
		//return range_error;
		return rangeError;
	Node<List_entry> *new_node, *previous, *following;
	if (position > 0) 
	{
		previous = set_position(position - 1);
		following = previous->next;
	}
    else
		following = head;
	
	new_node = new Node<List_entry>(x, following);



	if(new_node == NULL) 
		return overflow;
	if(position == 0)
		head=new_node;
	else
		previous->next = new_node;
	count++;
	return success;

}


template <class List_entry>
Error_code LinkedList<List_entry>::remove(int position)
/*
Post: If the List is not full and 0 <= position <= n,
      where n is the number of entries in the List, the function succeeds:
      Any entry formerly at position and all later entries have their
      position numbers increased by 1 and x is inserted at position of the List.
      Else: the function fails with a diagnostic error code.
*/
{
   
	if (position < 0 || position > count) 
		//return range_error;
		return rangeError;
	
	Node<List_entry> *previous, *del_node;
	
	del_node = new Node<List_entry>();

	if(del_node == NULL) 
		return overflow;

	if (position > 0) 
	{
		previous = set_position(position - 1);
		del_node = previous->next;
		previous->next = (previous->next)->next;
		delete del_node;
		count--;
	}
    
	
	if(position == 0)
	{
		if(count != 0)
		{
			del_node = head;
			head=head->next;
			delete del_node;
			count--;
		}
	}
	
	return success;

}

template <class List_entry>
void LinkedList<List_entry>::traverse(void (*visit)(List_entry &x))
/*
Pre:  position is a valid position in the List: 0 <= position < count.
Post: The current Node pointer references the Node at position.
*/
{
   Node <List_entry> *q = head;
   while(q != NULL)
   {
	   x = q;
	   (*visit)(x);
	   q = q->next;
   }
	   
}


/*
template <class List_entry>
void LinkedList<List_entry>::print(List_entry &x)

Pre:  position is a valid position in the List: 0 <= position < count.
Post: The current Node pointer references the Node at position.

{
   cout << x << " ";
	  
   
	   
}
*/



template <class List_entry>
void print(List_entry &x)
{
   cout << x << " " << endl;
	   
}

template <class List_entry>
void LinkedList<List_entry>::printList()
/*
Pre:  position is a valid position in the List: 0 <= position < count.
Post: The current Node pointer references the Node at position.
*/
{
   //traverse(print);   
	if(count == 0)
	{
		cout << "\nThe list is empty...\n\n";
		return;
	}
	Node <List_entry> *q = head;
	cout<< "Contents of the list (Starting at the head) :\n\n";
	for(int i = 0; i < count; i++)
	//while(q != NULL)
	{
	   
	   (*q).print();
	   q = q->next;
   }
	   
}

