#ifndef _TREET_H_INCLUDED_
#define _TREET_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// TreeT.h
// -------
// Binary tree template implementation                                   
//
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2016 Bjoern Lemke 
//
// INTERFACE MODULE
//
// Class: TreeT template class
// 
// Description: Native template binary tree implementation (not balanced)
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

template <class T>
class TreeT {
    
public:
    
    TreeT();
    TreeT(const TreeT<T>& x);
    ~TreeT();
    bool isEmpty() const;
    void Empty();
    bool Insert(const T& element);
    bool Remove(const T& element);
    T* Find(const T& element) const;
    T* First() const;
    T* Next() const;
    
    unsigned long Size() const;
    
    void* getTreePointer();
    void setTreePointer(void* treePointer);
    
    TreeT<T>& operator = (const TreeT<T>& x);
    bool operator == (const TreeT<T>& x) const;
    bool operator < (const TreeT<T>& x) const;
    bool operator > (const TreeT<T>& x) const;
        
private:
    
    class TreeElement {
	
    public:
	
	TreeElement() {
	    prev=0;
	    left=0;
	    right=0;
	}
	
	~TreeElement() {
	}
	
	T element;
	TreeElement* prev;
	TreeElement* left;
	TreeElement* right;	
    };
        
    TreeElement* getFirst() const
    {
	TreeElement* pElement = _rootElement;
	
	if (pElement)
	{	
	    while (pElement->left)
	    {
		pElement = pElement->left;
	    }
	    if (pElement)
	    {	
		return pElement;	
	    }
	    else
	    {
		return (TreeElement*)0;
	    }
	}
	return (TreeElement*)0;
    }
        
    TreeElement* getNext(TreeElement* pElement) const
    {
	if (pElement)
	{
	    if (pElement->right)
	    {	    
		pElement = pElement->right;
		while (pElement->left)
		{
		    pElement = pElement->left;
		}
		return pElement;
	    }
	    else
	    {
		if (pElement->prev)
		{	
		    if (pElement->prev->left == pElement)
		    {		    
			pElement = pElement->prev;
			return pElement;
		    }
		    else
		    {
			while (pElement->prev->left != pElement)
			{
			    pElement = pElement->prev;
			    if (!pElement->prev) 
			    {
				return (TreeElement*)0;
			    }			
			}
			pElement = pElement->prev;
			return pElement;
		    }		
		}
		else
		{
		    return (TreeElement*)0;
		}	    
	    }
	}
	return (TreeElement*)0;
    }
    
    TreeElement* _rootElement;
    TreeElement* _treePointer;
    unsigned long _size;
};

template<class T> TreeT<T>::TreeT()
{
    _rootElement = 0;
    _treePointer = 0;	
    _size = 0;
}

template<class T> TreeT<T>::TreeT(const TreeT<T>& x)
{    
    _rootElement = 0;
    _treePointer = 0;
    _size = 0;

    if (x._rootElement) 
    {	
	_rootElement = new TreeElement;
	_rootElement->prev=0;
	_rootElement->left=0;
	_rootElement->right=0;
	_rootElement->element = x._rootElement->element;
	_size++;
    }
    TreeElement* sourcePointer = x._rootElement;    
    TreeElement* targetPointer = _rootElement;    
    
    while (sourcePointer)
    {
	if (sourcePointer->left)
	{	    
	    sourcePointer = sourcePointer->left;
	    targetPointer->left = new TreeElement;
	    targetPointer->left->prev = targetPointer;	    
	    targetPointer = targetPointer->left;
	    targetPointer->element = sourcePointer->element;
	    targetPointer->left = 0;
	    targetPointer->right = 0;	    
	    _size++;
	}
	else if (sourcePointer->right)
	{
	    sourcePointer = sourcePointer->right; 
	    targetPointer->right = new TreeElement;
	    targetPointer->right->prev = targetPointer;	    
	    targetPointer = targetPointer->right;
	    targetPointer->element = sourcePointer->element;
	    targetPointer->left = 0;
	    targetPointer->right = 0;
	    _size++;
	} 
	else    
	{
	    if (sourcePointer->prev)
	    {		
		while(sourcePointer->prev->right == sourcePointer)
		{
		    sourcePointer = sourcePointer->prev;
		    targetPointer = targetPointer->prev;		    
		    if (!sourcePointer->prev)
		    {
			return;
		    }		    
		}
		TreeElement* prevPointer=sourcePointer;		
		sourcePointer = sourcePointer->prev;
		targetPointer = targetPointer->prev;
		while (sourcePointer->right == prevPointer || sourcePointer->right == 0)
		{		 
		    prevPointer = sourcePointer;			
		    sourcePointer = sourcePointer->prev;
		    targetPointer = targetPointer->prev;		    
		    if (!sourcePointer)
		    {
			return;		  		    
		    } 		    		    
		} 
		sourcePointer = sourcePointer->right;
		targetPointer->right = new TreeElement;
		targetPointer->right->prev = targetPointer;
		targetPointer = targetPointer->right;
		targetPointer->element = sourcePointer->element;	      
		targetPointer->left = 0;
		targetPointer->right = 0;
		_size++;
	    }
	    else
	    {
		return;
	    }	    
	}
    }  
    return;    
}

template<class T> TreeT<T>::~TreeT()
{
    while (_rootElement)
    {
	Remove(_rootElement->element);
    }
    _size = 0;
    _rootElement = 0;
    _treePointer = 0;
}

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

template<class T> void TreeT<T>::Empty()
{
    while (_rootElement)
    {
	Remove(_rootElement->element);
    }
    _size = 0;
    _rootElement = 0;
    _treePointer = 0;
}

template<class T> bool TreeT<T>::Insert(const T& element)
{   
    if (_rootElement)
    {
	TreeElement* pElement = _rootElement;
	TreeElement* pPrevElement;
	
	bool allocated = false;
	
	while (!allocated)
	{	    

	    pPrevElement=pElement;
	    
	    if (pElement->element < element)
	    {
 		if (pElement->right)
		{
		    pElement=pElement->right;
		}		
		else
		{		   
		    
		    // insert in right position
		    pElement->right = new TreeElement;
		    
		    pElement = pElement->right;
		    
		    allocated = true;		    
		}		
	    }
	    else if (pElement->element > element)
	    {
		if (pElement->left)
		{		    
		    pElement=pElement->left;
		}
		else
		{
		    
		    // insert in left position
		    pElement->left = new TreeElement;
		    
		    pElement = pElement->left;
		    
		    allocated = true;		    
		}		
	    }
	    else
	    {	       		
		return false;
	    }	    
	}
	
	_size++;
	pElement->prev = pPrevElement;
	pElement->left = 0;
	pElement->right = 0;
	pElement->element = element;

	return true;	
    }    
    else
    {    
	_rootElement = new TreeElement;
	_rootElement->element = element;
	_rootElement->prev=0;
	_rootElement->left=0;
	_rootElement->right=0;
	_size++;
	return true;	
    }
}

template<class T> bool TreeT<T>::Remove(const T& element)
{
    TreeElement* pElement = _rootElement;
    
    bool found = false;
    
    while (pElement && !found)
    {
	if (pElement->element < element)
	{
	    pElement = pElement->right;
	}
	else if (pElement->element > element)
	{
	    pElement = pElement->left;
	}
	else
	{
	    found = true;
	}	
    }
    
    if (found)
    {
	if (pElement->right == 0)
	{
	    if (pElement == _rootElement)
	    {
		_rootElement = pElement->left;
		if (_rootElement != 0)
		{		    
		    _rootElement->prev = 0;
		}
		delete pElement;		
	    }
	    else
	    {		
		if (pElement == pElement->prev->right)
		{		
		    pElement->prev->right = pElement->left;
		    if (pElement->left)
		    {			
			pElement->left->prev = pElement->prev;
		    }		    
		}	    
		else
		{
		    pElement->prev->left = pElement->left;
		    if (pElement->left)
		    {			
			pElement->left->prev = pElement->prev;		    
		    }		    
		}
	        delete pElement;		
	    }	    
	} 
	else if (pElement->left == 0)
	{
	    if (pElement == _rootElement)
	    {
		_rootElement = pElement->right;
		if (_rootElement != 0)
		{		    
		    _rootElement->prev = 0;
		}		
		delete pElement;		
	    }
	    else
	    {		
		if (pElement == pElement->prev->right)
		{		
		    pElement->prev->right = pElement->right;
		    if (pElement->right)
		    {			
			pElement->right->prev = pElement->prev;
		    }		   
		}	    
		else
		{		    		    
		    pElement->prev->left = pElement->right;
		    if (pElement->right)
		    {			
			pElement->right->prev = pElement->prev;		    
		    }		    
		}		
		delete pElement;		
	    }	    
	}
	else 
	{
	    // search largest element in left subtree
	    TreeElement* largestElement = pElement->left;
	    while (largestElement->right)
	    {		
		largestElement = largestElement->right;
	    }
	    if (largestElement->prev == pElement)
	    {	
		pElement->left = largestElement->left;
		if (pElement->left)
		{		    
		    pElement->left->prev = pElement;
		}		
		pElement->element = largestElement->element;		
		delete largestElement;
	    }
	    else
	    {
		largestElement->prev->right = largestElement->left;
		if (largestElement->left)
		{		    
		    largestElement->left->prev = largestElement->prev;
		}
		pElement->element = largestElement->element;
		delete largestElement;
	    }
	}
	_size--;
	return true;	
    }	
    else
    {
	return false;
    }
}

template<class T> T* TreeT<T>::Find(const T& element) const
{
    TreeElement* pElement = _rootElement;
    
    while (pElement)
    {
	if (pElement->element < element)
	{
	    pElement = pElement->right;
	}
	else if (pElement->element > element)
	{
	    pElement = pElement->left;
	}
	else
	{
	    return (&(pElement->element));
	}	
    }
    return (T*)0;    
}

template<class T> T* TreeT<T>::First() const
{
    ((TreeT<T>*)this)->_treePointer = getFirst();
    if (_treePointer)
    {
	return (&(_treePointer->element));
    }
    else
    {
	return (T*)0;
    }    
}

template<class T> T* TreeT<T>::Next() const
{
    
    ((TreeT<T>*)this)->_treePointer = getNext(_treePointer);
    
    if (_treePointer)
    {
	return (&(_treePointer->element));
    }
    else
    {
	return (T*)0;
    }    
}

template<class T> unsigned long TreeT<T>::Size() const
{
    return _size;
}

template<class T> void* TreeT<T>::getTreePointer()
{
    return (void*)_treePointer;
}

template<class T> void TreeT<T>::setTreePointer(void* treePointer)
{
    _treePointer = (TreeElement*)treePointer;
}

template<class T> TreeT<T>& TreeT<T>::operator=(const TreeT<T>& x)
{    
    Empty(); 
    _rootElement = 0;
    _treePointer = 0;	 
    _size=0;

    if (x._rootElement) 
    {	
	_rootElement = new TreeElement;
	_rootElement->prev=0;
	_rootElement->left=0;
	_rootElement->right=0;	
	_rootElement->element = x._rootElement->element;
	_size++;
    }
    TreeElement* sourcePointer = x._rootElement;    
    TreeElement* targetPointer = _rootElement;    
  
    while (sourcePointer)
    {
	if (sourcePointer->left)
	{	    
	    sourcePointer = sourcePointer->left;
	    targetPointer->left = new TreeElement;
	    targetPointer->left->prev = targetPointer;	    
	    targetPointer = targetPointer->left;
	    targetPointer->element = sourcePointer->element;
	    targetPointer->left = 0;
	    targetPointer->right = 0;	    
	    _size++;
	}
	else if (sourcePointer->right)
	{
	    sourcePointer = sourcePointer->right; 
	    targetPointer->right = new TreeElement;
	    targetPointer->right->prev = targetPointer;	    
	    targetPointer = targetPointer->right;
	    targetPointer->element = sourcePointer->element;
	    targetPointer->left = 0;
	    targetPointer->right = 0;	    
	    _size++;
	} 
	else    
	{
	    if (sourcePointer->prev)
	    {		
		while(sourcePointer->prev->right == sourcePointer)
		{
		    sourcePointer = sourcePointer->prev;
		    targetPointer = targetPointer->prev;		    
		    if (!sourcePointer->prev)
		    {
		      return (*this);
		    }		    
		}
		TreeElement* prevPointer=sourcePointer;		
		sourcePointer = sourcePointer->prev;
		targetPointer = targetPointer->prev;
		while (sourcePointer->right == prevPointer || sourcePointer->right == 0)
		{		 
		    prevPointer = sourcePointer;			
		    sourcePointer = sourcePointer->prev;
		    targetPointer = targetPointer->prev;		    
		    if (!sourcePointer)
		    {
			return (*this);		  		    
		    } 		    		    
		} 
		sourcePointer = sourcePointer->right;
		targetPointer->right = new TreeElement;
		targetPointer->right->prev = targetPointer;
		targetPointer = targetPointer->right;
		targetPointer->element = sourcePointer->element;	      
		targetPointer->left = 0;
		targetPointer->right = 0;	    
		_size++;
	    }
	    else
	    {
		return (*this);
	    }	    
	}
    }
    return (*this);
}
    
template<class T> bool TreeT<T>::operator==(const TreeT<T>& x) const
{
    
    TreeElement* pElement1 = getFirst();
    TreeElement* pElement2 = x.getFirst();
    
    while (pElement1 && pElement2)
    {
	if (pElement1->element == pElement2->element)
	{
	    pElement1 = getNext(pElement1);
	    pElement2 = x.getNext(pElement2);
	}
	else
	{
	    return false;
	}
    }
    
    if (pElement1 || pElement2)
    {
	return false;
    }
    else
    {
	return true;
    }
}
	
template<class T> bool TreeT<T>::operator < (const TreeT<T>& x) const
{
    
    TreeElement* pElement1 = getFirst();
    TreeElement* pElement2 = x.getFirst();
    
    while (pElement1 && pElement2)
    {

	if (pElement1->element < pElement2->element)
	{
	    return true;	    
	}
	else if (pElement1->element > pElement2->element)
	{
	    return false;
	}
	else
	{
	    pElement1 = getNext(pElement1);
	    pElement2 = x.getNext(pElement2);
	}
    }

    if (pElement1)
    {
	return false;
    }
    else if (pElement2)
    {
	return true;
    }
    else
    {
	return false;
    }

}

template<class T> bool TreeT<T>::operator > (const TreeT<T>& x) const
{

    TreeElement* pElement1 = getFirst();
    
    TreeElement* pElement2 = x.getFirst();
    
    while (pElement1 && pElement2)
    {
	if (pElement1->element > pElement2->element)
	{
	    return true;	    
	}
	else if (pElement1->element < pElement2->element)
	{
	    return false;
	}
	else
	{
	    pElement1 = getNext(pElement1);
	    pElement2 = x.getNext(pElement2);
	}
    }
    
    if (pElement1)
    {
	return true;
    }
    else if (pElement2)
    {
	return false;
    }
    else
    {
	return false;
    }
}

#endif
