//	Header File:	linked2.h
//	USING NESTED CLASSES
#ifndef    LINKED2_H
#define    LINKED2_H

#include <iostream>
using namespace std;

template <typename T=int>  //DEFAULT type is int
class myList
{
// Companion to class list
friend class ListIterator;  //Gives ListIterator access to myList private data

private:
	struct node;	//myList member ==> No need to template
	node *front;
	node *rear;

public:
	myList();		//Constructor
	myList(const myList &); //Copy Constructor
	
	~myList(); 		//Destructor	
	
	// Mutators	
	myList & add_front (const T);
	myList & remove_front ();
	myList & add_rear (const T);
	myList & remove_rear ();

	// Accessor
	bool empty() const;
	
	class ListIterator;  //myList member ==> No need to template
};

template <typename T>
struct myList<T>::node
{
	T	data;
	node	*next;
};
	
template <typename T>
class myList<T>::ListIterator
{
private:
	node *current;
public:	
	ListIterator(const myList<T> &); //Constructor
	ListIterator(const ListIterator &); //Copy Constructor
	
	//"next" places data from current node into
	//parameter and advances current pointer
	//returns true if successful
	//false if at end of list
	bool next(T &);
};

/****************************************************************************/

//list IMPLEMENTATION
template <typename T> 
myList<T>::myList()	//Constructor
:	front(NULL), rear(NULL) //member initializer list
{
}

template <typename T> 
myList<T>::myList(const myList & L) //Copy Constructor
{
	
	front=rear=NULL;
	for (node *temp = L.front; temp!=NULL; temp=temp->next)
	{
		add_rear(temp->data);
	}
}
		

template <typename T> 
myList<T>::~myList() //Destructor
{
	node *temp;
	while (front!=NULL)
	{
		temp = front->next;
		delete front;
		front = temp;
	}
}

	
template <typename T> 
myList<T> & myList<T>::add_front (const T number)
{
	node * temp=new node;

	temp->data=number;
	temp->next=front;
	front=temp;

	if (rear==NULL)	//list empty to start
		rear=front;

	return *this;
}


//Pre-Condition:  Non-empty list
template <typename T> 
myList<T> & myList<T>::remove_front ()
{
	node * temp=front;

	front=front->next;
	delete temp;

	if (front==NULL)	//list empty
		rear=NULL;

	return *this;
}

template <typename T> 
myList<T> & myList<T>::add_rear (const T number)
{
	node * temp = new node;

	temp->data=number;
	temp->next=0;
	if (rear!=NULL)
		rear->next=temp;
	rear=temp;

	if (front==NULL)	//list empty to start
		front=rear;

	return *this;
}
	
//Pre-Condition:  Non-empty list
template <typename T> 
myList<T> & myList<T>::remove_rear ()
{
	node *p, *followp=NULL;

	for (p=front; p!=rear; p=p->next)
		followp=p;

	if (followp!=NULL)
		followp->next=0;
	delete p;

	rear=followp;
	if (rear==NULL)	//list empty
		front=NULL;

	return *this;
}

template <typename T> 
bool myList<T>::empty() const
{
	return (front==NULL);
}


/*************************************************************************/
// ListIterator IMPLEMENTATION
template <typename T>
myList<T>::ListIterator::ListIterator(const myList<T> & L) //Constructor
:	current(L.front)
{
}

template <typename T>
myList<T>::ListIterator::ListIterator(const ListIterator & I) //Copy Constructor
:	current(I.current)
{
}
	
	//"next" places data from current node <T> into
	//parameter and advances current pointer
	//returns true if successful
	//false if at end of list

template <typename T>
bool myList<T>::ListIterator::next(T & number)
{
	if (current==NULL)
		return false;

	number = current->data;
	current = current->next;

	return true;
}
/*****************************OVERLOADED OPERATORS*******************************/
//	Auxiliary function IMPLEMENTATION
template <typename T>
ostream & operator<< (ostream & out, const myList<T> & L)
{
	T data;
	
	myList<T>::ListIterator	i(L);
	while (i.next(data))
	{
		out << data << endl;
	}

	return out;
}

#endif
