#ifndef _SETT_H_INCLUDED_
#define _SETT_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// SetT.h
// ------
// SetT template class definition and implementation
//
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2019 Bjoern Lemke
//
// TEMPLATE CLASS
//
// Class: SetT
//
// Description: Template Class for Sets
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

template<class T>
class SetT {
    
 public: 
    SetT();
    SetT(const SetT<T>& s);
    ~SetT();
    bool isEmpty() const;
    void Empty();
    int Size() const;
    bool Insert(const T& element);
    bool Remove(const T& element);
    T* Find(const T& element) const;
    T* First() const;
    T* Next(void* m = 0) const;
    
    SetT<T>& operator += (SetT<T>& s);
    SetT<T>& operator -= (SetT<T>& s);
    SetT<T>& operator ^= (SetT<T>& s);
    SetT<T>& operator = (const SetT<T>& s);
    SetT<T> operator + ( SetT<T>& s);
    SetT<T> operator - ( SetT<T>& s);
    bool operator == (const SetT<T>& s) const;
    
 private:
    
    class SetElement;

    SetElement* _setBase;
    SetElement* _setPointer;

    int _numElement;

    class SetElement {
	
    public:
	
	SetElement(const T& element) {
	    _element = element;
	    _next=0;
	}	
	~SetElement() {}
	T _element;
	SetElement* _next;
	
    };
};

template<class T> SetT<T>::SetT()
{
    _setBase = 0;
    _setPointer = 0;
    _numElement = 0;
}

template<class T> SetT<T>::SetT(const SetT& s)
{
    _setBase = 0;  
    SetElement* pElement = s._setBase;
    while (pElement)
    {
	Insert(pElement->_element);
	pElement = pElement->_next;
    }
    _setPointer = 0;
    _numElement = s._numElement;
}

template<class T> SetT<T>::~SetT()
{
    if (_setBase != 0)
    {
	SetElement* pElement = _setBase;
	while (pElement)
	{
	    _setBase = _setBase->_next;
	    delete pElement;
	    pElement = _setBase;
	}   
    }
}

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

template<class T> void SetT<T>::Empty()
{
    if (_setBase != 0)
    {
	SetElement* pElement = _setBase;
	while (pElement)
	{
	    _setBase = _setBase->_next;	    
	    delete pElement;
	    pElement = _setBase;
	} 
    }
    _numElement = 0;
}

template<class T> int SetT<T>::Size() const
{
    return _numElement;
}

template<class T> bool SetT<T>::Insert(const T& element)
{

    SetElement* pElement = _setBase;
    
    while (pElement)
    {
	if (pElement->_element == element)
	    return (false);
	pElement = pElement->_next;
    }
    // insert new element now    
    pElement = new SetElement(element);
    // pElement->element = element;
    pElement->_next = _setBase;
    _setBase = pElement;
    
    _numElement++;

    return (true);
}

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

    SetElement* pElement = _setBase;
    SetElement* pPrevElement = _setBase;
    
    // list not empty
    if (pElement != 0)
    { 
	while (pElement)
	{
	    if (pElement->_element == element)
	    {		
		// remove element now
		if (pElement == pPrevElement)
		{
		    // first element in list 
		    _setBase = _setBase->_next;
		    delete pElement;
		}
		else
		{
		    pPrevElement->_next = pElement->_next;
		    delete pElement;
		    
		}

		_numElement--;

		return (true);
	    }
	    else 
	    {
		pPrevElement = pElement;
		pElement = pElement->_next;
	    }
	}
	return (false);
    }
    else
    {
	return (false);
    }
}

template<class T> T* SetT<T>::Find(const T& element) const
{
    if (_setBase != 0)
    {
	SetElement* pElement = _setBase;
	while (pElement)
	{
	    if (pElement->_element == element)
	    {
		return (&(pElement->_element));
	    }
	    pElement = pElement->_next;
	}
	return (0);
    }    
    return (0);
}

template<class T> T* SetT<T>::First() const
{
    if (_setBase == 0)
    {
	return (T*)0;
    }
    else
    {
	((SetT<T>*)this)->_setPointer = _setBase;
	return (&(_setPointer->_element));
    }
}    

template<class T> T* SetT<T>::Next(void* m) const
{
    if (m != 0)
    {
	((SetT<T>*)this)->_setPointer = (SetElement*)m;
    }

    if (_setPointer == 0)
    {
	return (T*)0;
    }
    else
    {
	((SetT<T>*)this)->_setPointer = _setPointer->_next;
	if (_setPointer != 0)
	{
	    return (&(_setPointer->_element));
	}
	else
	{
	    return (T*)0;
	}
    }
}

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

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

template<class T> SetT<T>& SetT<T>::operator^=(SetT<T>& s)
{
    T* commonElement = First();
    while (commonElement)
    {
	if (!s.Find(*commonElement))
	{
	    Remove(*commonElement);
	    commonElement = First();
	}
	else
	{
	    commonElement = Next();
	}
    }
    return (*this);
}

template<class T> SetT<T>& SetT<T>::operator=(const SetT<T>& s)
{
    Empty();
    SetElement* pElement = s._setBase;
    while (pElement)
    {
	Insert(pElement->_element);
	pElement = pElement->_next;
    }
    _setPointer = 0;
    return (*this);
    
}

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

    SetT<T> mergeSet;
    
    mergeSet = s;

    _setPointer = _setBase;
    while (_setPointer) 
    {
	mergeSet.Insert(_setPointer->_element);
	_setPointer = _setPointer->_next;
    }
    
    return mergeSet;
}

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

    SetT<T> diffSet;

    diffSet = *this;

    T* diffElement = s.First();
    while (diffElement)
    {
	diffSet.Remove(*diffElement);
	diffElement = s.Next();
    }
    return (diffSet);
}

template<class T> bool SetT<T>::operator == (const SetT<T>& s) const
{
    if ( _numElement != s._numElement)
    {
	return false;
    }
    
    ((SetT<T>*)this)->_setPointer = _setBase;
    while (_setPointer) 
    {
      if ( ! s.Find(_setPointer->_element) )
	     return false;
	((SetT<T>*)this)->_setPointer = _setPointer->_next;
    }
    
    return true;
}

#endif
