// © Copyright 1995. Joseph Bergin. All rights reserved.

#ifndef __List__
#define __List__

#include <iostream.h>
#include "Error.h"
#include "Boolean.h"


//*********************  NODE   **************************
template <class E>
class ListNode
{ // no public:
		ListNode(const E& e):_next(NULL), _value(e){};
		ListNode(const ListNode<E>& n): _next(n._next), _value(n._value){};
		~ListNode(){};
		ListNode& operator = (const ListNode<E> &n)
		{	if(this != &n)
			{	_next = n._next; 
				_value = n._value;
			}
			return *this;
		}
		
	private:
		ListNode<E>* _next;
		E _value;
		
		ListNode* copyAll()
		{	ListNode<E> *result;
			result = new ListNode<E>(_value);
			FAILNULL(result);
			if(_next != NULL)
				result->_next = _next->copyAll();
			return result;
		}

#ifdef _DebugLists_		
	void dump()
	{	cout << _value << ' ';
		if(_next != NULL) _next->dump();
	}
#endif

	friend class List<E>;
	friend ostream & operator<<(ostream & os, const List<E>& L);
};

// ****************** LIST   ******************************
template<class E>
class List
{	public:
		List():	_first(NULL){}
		
		List(const List<E> &t) // copy constructor
		{	copy(t);
		}
		
		List<E> & operator =(const List<E> &L)
		{	if(this != &L)
			{	free();
				copy(L);
			}
			return *this;		
		}

		~List()
		{	free();
		}
		
		Boolean empty() const
		{	return Boolean(_first == NULL);
		}
		
		E head() const
		{	if(_first == NULL) userERROR("Empty list has no head.");
			return _first->_value;
		}
		
		List<E> tail() const
		{	if(_first == NULL) userERROR("Empty list has no tail.");
			List<E> result;
			if(_first->_next != NULL)
				result._first = _first->_next->copyAll();
			return result;
		}
		
		List<E> consElement(const E& e) const
		{	List<E> result(*this);
			ListNode<E> *first = new ListNode<E>(e);
			FAILNULL(first);
			first->_next = result._first;
			result._first = first;
			return result;
		}

//unsigned int length( ); 

#ifdef _DebugLists_				
		void dump() const{_first->dump();cout<<endl;}
#endif
		
	private:
		ListNode<E>* _first;

		void free()
		{	ListNode<E> *temp;
			while(_first != NULL)
			{	temp = _first->_next;
				delete _first;
				_first = temp;
			}
		}

		void copy(const List& t)
		{	if(t._first != NULL)
				_first = t._first->copyAll();
			else 
				_first = NULL;
		}

	friend ostream & operator<<(ostream & os, const List<E>& L);
};

template <class E> 
List<E> operator +(const E& e, const List<E>& t)
{	return t.consElement(e);
}

template <class E> 
List<E> cons(const E& e, const List<E>& t)
{	return t.consElement(e);
}

/*
template <class E>
unsigned int List<E>::length()
{	unsigned int result = 0;
	ListNode<E> * n = _first; // Important, a ListNode pointer.
	while ( n != NULL)
	{	result++;
		n = n->_next;
	}
	return result;
}
*/

template <class E>
ostream & operator<<(ostream & os, const List<E>& L)
{  ListNode<E> *n = L._first;
	while(n != NULL)
	{	os << n->_value<<' ';
   	n = n->_next;
	}
	return os;
}


#endif

