#ifndef LIST_HPP
#define	LIST_HPP

#include "C:\L\List\Node.h"

template <class TYPE>
class List
{
public:
	List();
	~List();

	void			insertFront		(const TYPE &newData);
	void			insertBack		(const TYPE &newData);

	bool			removeFront		(TYPE &);
	bool			removeBack		(TYPE &);
	
	bool			isEmpty			() const;
	void			print			(unsigned int index) const;
	void			getNodes		(unsigned int i, TYPE &whereTo) const;
	void			deleteNode		(const TYPE &deleteItem);
	void			deleteNodeByRef	(int Index);
	bool			changeData		(unsigned int index, TYPE &whereFrom);

	void			popFront		();
	int				length			() const;
	int				GetLength		() const;

	Node<TYPE> *	getFirst		();
	Node<TYPE> *	getPtrToNode	(int index);

private:
	Node<TYPE>		*first;
	Node<TYPE>		*last;
	Node<TYPE>		*getNewNode(const TYPE &newData);
	int				listLength;
};
template <class TYPE>
List<TYPE>::List() : first(0), last(0), listLength(0)
{
	/* Empty constructor - functionality in declaration */
}
template <class TYPE>
List<TYPE>::~List()
{
	if(!isEmpty())
	{
		Node<TYPE> *current = first;
		Node<TYPE> *temp;
		while(current != NULL)
		{
			temp = current;
			current = current->next;
			delete temp;
		}//end: while
	}//end: if
}
template <class TYPE>
void List<TYPE>::insertFront(const TYPE &newData)
{
	Node<TYPE> *newPtr = getNewNode(newData);
	if(isEmpty())	first = last = newPtr;
	else			{ newPtr->next = first; first = newPtr; }
	if(isEmpty() == false) listLength++;
}
template <class TYPE>
void List<TYPE>::insertBack(const TYPE &newData)
{
	Node<TYPE> *newPtr = getNewNode(newData);
	if(newPtr == NULL) return;
	if(isEmpty()) first = last = newPtr;
	else { last->next = newPtr; last = newPtr; }
	if(isEmpty() == false) listLength++;
}
template <class TYPE>
bool List<TYPE>::removeFront(TYPE &value)
{
	if(isEmpty()) return false;
	else
	{
		Node<TYPE> *temp = first;
		if(first == last)	first = last = 0;
		else				first = first->next;
		value = temp->Data; delete temp;
		length--;
	}
	return true;
}
template <class TYPE>
void List<TYPE>::popFront()
{
	if(isEmpty())	return;
	else
	{
		Node<TYPE> *temp = first;
		if(first == last)	first = last = 0;
		else				first = first->next;
		delete temp;
		listLength--;
	}
}
template <class TYPE>
bool List<TYPE>::removeBack(TYPE &value)
{
	if(isEmpty())
		return false;
	else
	{
		Node<TYPE> *temp = last;

		if(first == last)
			first = last = 0;
		else
		{
			Node<TYPE> *current = first;

			while(current->next != last)
				current = current->next;

			last = current;
			current->next = 0;
		}

		value = temp->Data;
		delete temp;
		length--;
		return true;
	}
}
template <class TYPE>
bool List<TYPE>::isEmpty() const
{
	//Returns TRUE if the list is indeed empty
	return (first == NULL);
}
template <class TYPE>
Node<TYPE> *List<TYPE>::getNewNode(const TYPE &newData)
{
	return new Node<TYPE>(newData);
}
template <class TYPE>
void List<TYPE>::print(unsigned int index) const
{
	unsigned int counter = 0;
	if(isEmpty()) return;
	Node<TYPE> *current = first;
	while(current != 0)
	{
		if(counter == index)
		{
		//	cout << current->Data;
		}
		++counter;
		current = current->next;
	}
//	cout << "\n\n";
}
template <class TYPE>
void List<TYPE>::getNodes(unsigned int index, TYPE &whereTo) const
{
	if(isEmpty()) return;
	unsigned int counter; counter = 0; Node<TYPE> *current = first;
	while(current != NULL)
	{
		if(counter == index) { whereTo = current->Data; current = NULL; return; }
		current = current->next; ++counter;
	}
}
template <class TYPE>
bool List<TYPE>::changeData(unsigned int index, TYPE &whereFrom)
{
	unsigned int counter;
	Node<TYPE> *current = first;

	if(isEmpty()) return false;
	counter = 0;

	while(current != 0)
	{
		if(counter == index)
		{
			current->Data = whereFrom;
			return true;
		}
		current = current->next;
		++counter;
	}
	return false;
}
template <class TYPE>
int List<TYPE>::length() const
{
	int counter;
	if(isEmpty() == true) return 0;
	counter = 0;
	Node<TYPE> *current = first;
	while(current != NULL) { counter++; current = current->next; }
	return counter;
}
template <class TYPE>
int List<TYPE>::GetLength() const
{
	return listLength;
}
template <class TYPE>
void List<TYPE>::deleteNode(const TYPE &deleteItem)
{
	Node<TYPE> *current; Node<TYPE> *trailCurrent; bool found = false;
	if(first == NULL) return;
	else
	{
		if(first->Data == deleteItem)
		{
			current = first; first	= first->next;
			if(first == NULL) last = NULL; delete current;
			length--;
		}
		else
		{
			found = false; trailCurrent = first; current = first->next;
			while((!found) && (current != NULL))
			{
				if(current->Data != deleteItem) { trailCurrent = current; current = current->next; }
				else found = true;
			}
			if(found == true)
			{
				trailCurrent->next = current->next;
				if(last == current) last = trailCurrent;
				delete current;
				length--;
			}
		}
	}
}
template <class TYPE>
void List<TYPE>::deleteNodeByRef(int Index)
{
	Node<TYPE> *current;
	Node<TYPE> *trailCurrent;
	int Count = 0;

	if(first == NULL) return;
	else
	{
		if(Count == Index)
		{
			current = first;
			first = first->next;
			if(first == NULL) last = NULL;
			delete current;
			listLength--;
		}
		else
		{
			trailCurrent	= first;
			current			= first->next;
			while(Count != Index && current != NULL)
			{
				Count++;
				if(Count == Index)
				{
					trailCurrent->next = current->next;
					if(last == current) last = trailCurrent;
					delete current;
					listLength--;
				}
				else 
				{
					trailCurrent	= current;
					current			= current->next;
				}
			}
		}
	}
}
template <class TYPE>
Node<TYPE>* List<TYPE>::getFirst()
{
	return first;
}
template <class TYPE>
Node<TYPE>* List<TYPE>::getPtrToNode(int i)
{
	unsigned int counter;

	if(isEmpty()) return;
	counter = 0; Node<TYPE> *current = first;
	while(current != 0)
	{
		if(counter + 1 == i) return current->next;
		current = current->next;
		++counter;
	}
	return NULL;
}
#endif