#ifndef _LISTT_H_INCLUDED_
#define _LISTT_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// ListT.h
// --------
// ListT class definition 
//                                                        
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2016 Bjoern Lemke
//
// TEMPLATE CLASS
// 
// Class: ListT
//
// Description: Template Class for Lists
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

#include "Exception.h"

template<class T>
class ListT {
    
public: 
    ListT();
    ListT(const ListT&);
    ~ListT();
    bool isEmpty() const;
    void Empty();
    void Insert(const T& element);
    bool Remove(const T& element);
    T* Find(const T& element) const;
    T* First() const;
    T* Next() const;
    
    int Size() const;
    
    T& operator [] (int i) const;
    ListT<T>& operator += (const ListT<T>& s);
    ListT<T>& operator -= (const ListT<T>& s);
    ListT<T>& operator = (const ListT<T>& s);
    ListT<T> operator + ( const ListT<T>& s) const;
    ListT<T> operator - ( const ListT<T>& s) const;
    bool operator == (const ListT<T>& s) const;    
    
private:
    
    class ListElement;

    ListElement* _listBase;
    ListElement* _listPointer;
    ListElement* _listEnd;
    
    class ListElement {
	
    public:
	
	ListElement() 
	{
	    next=0;
	}
	~ListElement() 
	{
	}
	
	
	T element;
	ListElement* next;
	
    };
};

template<class T> ListT<T>::ListT()
{
    _listBase = 0;
    _listPointer = 0;
    _listEnd = 0;
}

template<class T> ListT<T>::ListT(const ListT& x)
{
    _listBase = 0;
    _listEnd = 0;
    ListElement* pElement = x._listBase;
    while (pElement)
    {
	Insert(pElement->element);
	pElement = pElement->next;
    }
    _listPointer = 0;
}

template<class T> ListT<T>::~ListT()
{
    if (_listBase != 0)
    {
	ListElement* pElement = _listBase;
	while (pElement)
	{
	    _listBase = _listBase->next;
	    delete pElement;
	    pElement = _listBase;
	}   
    }
}

template<class T> bool ListT<T>::isEmpty() const
{
    if (_listBase == 0)
    {
	return (true);
    }
    return false;
}

template<class T> void ListT<T>::Empty()
{
    if (_listBase != 0)
    {
	ListElement* pElement = _listBase;
	while (pElement)
	{
	    _listBase = _listBase->next;	    
	    delete pElement;
	    pElement = _listBase;
	}
	_listEnd = 0;
    }
}

template<class T> void ListT<T>::Insert(const T& element)
{
    if ( _listEnd )
    {	
	_listEnd->next = new ListElement;
	_listEnd->next->element = element;
	_listEnd = _listEnd->next;	
    }
    else
    {
	_listBase = new ListElement;
	_listEnd = _listBase;
	_listBase->element = element;	    
    }   
    return;
}

template<class T> bool ListT<T>::Remove(const T& element)
{

    ListElement* pElement = _listBase;
    ListElement* pPrevElement = _listBase;
    
    // list not empty
    if (pElement != 0)
    { 
	while (pElement)
	{
	    if (pElement->element == element)
	    {		
		// remove element now
		if (pElement == pPrevElement)
		{
		    // first element in list 
		    _listBase = _listBase->next;
		    if ( _listEnd == pElement )
			_listEnd = _listEnd->next;
		    delete pElement;
		}
		else
		{
		    pPrevElement->next = pElement->next;
		    if ( _listEnd == pElement )
			_listEnd = pPrevElement;
		    delete pElement;		    
		}
		return (true);
	    }
	    else 
	    {
		pPrevElement = pElement;
		pElement = pElement->next;
	    }
	}
	return (false);
    }
    else
    {
	return (false);
    }
}

template<class T> T* ListT<T>::Find(const T& element) const
{
    if (_listBase != 0)
    {
	ListElement* pElement = _listBase;
	while (pElement)
	{
	    if (pElement->element == element)
	    {
		return (&(pElement->element));
	    }
	    pElement = pElement->next;
	}
	return (0);
    }    
    return (0);
}

template<class T> T* ListT<T>::First() const
{
    if (_listBase == 0)
    {
	return (T*)0;
    }
    else
    {
	((ListT<T>*)this)->_listPointer = _listBase;
	return (&(_listPointer->element));
    }
}    

template<class T> T* ListT<T>::Next() const
{
    if (_listPointer == 0)
    {
	return (T*)0;
    }
    else
    {
	((ListT<T>*)this)->_listPointer = _listPointer->next;
	if (_listPointer != 0)
	{
	    return (&(_listPointer->element));
	}
	else
	{
	    return (T*)0;
	}
    }
}

template<class T> int ListT<T>::Size() const
{
    
    if (_listBase != 0)
    {
	int size=0;
	
	ListElement* pElement = _listBase;
	while (pElement)
	{
	    size++;

	    pElement = pElement->next;
	}
	return (size);
    }    
    return (0);
}

template<class T> T& ListT<T>::operator [] (int i) const
{
  
    if (_listBase != 0)
    {
	int j=0;
	ListElement* pElement = _listBase;
	while (pElement)
	{
	    if ( i == j)
	    {
		return ( pElement->element );
	    }
	    j++;
	    pElement = pElement->next;
	}
    }
   
    throw Exception(EXLOC, "list position exceeded");
    
}

template<class T> ListT<T>& ListT<T>::operator+=(const ListT<T>& s)
{
    T* mergeElement = s.First();
    while (mergeElement)
    {
        Insert(*mergeElement);
	mergeElement = s.Next();
    }
    return (*this);
}

template<class T> ListT<T>& ListT<T>::operator-=(const ListT<T>& s)
{
    T* mergeElement = s.First();
    while (mergeElement)
    {
        Remove(*mergeElement);
	mergeElement = s.Next();
    }
    return (*this);
}

template<class T> ListT<T>& ListT<T>::operator=(const ListT<T>& s)
{
    Empty();
    ListElement* pElement = s._listBase;
    while (pElement)
    {
	Insert(pElement->element);
	pElement = pElement->next;
    }
    _listPointer = 0;
    return (*this);
    
}

template<class T> ListT<T> ListT<T>::operator + (const ListT<T>& s) const
{

    ListT<T> mergeList;
    
    mergeList = *this;
    mergeList += s;
    
    return mergeList;
    
}

template<class T> ListT<T> ListT<T>::operator - (const ListT<T>& s) const
{

    ListT<T> mergeList;
    
    mergeList = *this;
    mergeList -= s;
    
    return mergeList;
    
}

template<class T> bool ListT<T>::operator == (const ListT<T>& s) const
{

    if ( _listBase && s._listBase  )
    {
	ListElement* pElement1 = _listBase;
	ListElement* pElement2 = s._listBase;
	
	while (pElement1 && pElement2)
	{
	    if (pElement1->element == pElement2->element)
	    {
		pElement1 = pElement1->next;
		pElement2 = pElement2->next;
	    }
	    else
	    {
		return false;
	    }

	}
	if ( pElement1 == 0 && pElement2 == 0)
	    return true;
	return false;
    }
    else if ( _listBase == 0 && s._listBase == 0 )
	return true;
    return false;
}

#endif
