#ifndef _STACKT_H_INCLUDED_
#define _STACKT_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// StackT.h
// ------_--
// StackT template class definition and implementation
//                                                         
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2016 Bjoern Lemke
//
// TEMPLATE CLASS
//
// Class: StackT
// 
// Description: Implementation of a generic stack 
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

template<class T>
class StackT {
    
public: 
    StackT();
    StackT(const StackT&);
    ~StackT();
    bool isEmpty() const;
    void Empty();
    void Push(const T& element);
    bool Pop(T& element);
    T* getTop() const;

    int Size() const;

    StackT<T>& operator = (const StackT<T>& s);
    
private:
    
    class StackElement;
    
    StackElement* _stackBase;
    
    class StackElement {
	
    public:
	
	StackElement() {
	    next=0;
	}
	
	T element;
	StackElement* next;
	
    };
};

template<class T> StackT<T>::StackT()
{
    _stackBase = 0;
}

template<class T> StackT<T>::StackT(const StackT& x)
{
    _stackBase = 0;
    for ( int i = x.Size() ; i > 0 ; i-- )
    {
	StackElement* pElement = x._stackBase;
	int j = 1;
	
	while (j < i )
	{
	    pElement = pElement->next;
	    j++;
	}
	Push(pElement->element);
    }
}

template<class T> StackT<T>::~StackT()
{
    if (_stackBase != 0)
    {
	StackElement* pElement = _stackBase;
	while (pElement)
	{
	    _stackBase = _stackBase->next;
	    delete pElement;
	    pElement = _stackBase;
	}   
    }
}

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

template<class T> void StackT<T>::Empty()
{
    if (_stackBase != 0)
    {
	StackElement* pElement = _stackBase;
	while (pElement)
	{
	    _stackBase = _stackBase->next;	    
	    delete pElement;
	    pElement = _stackBase;
	} 
    }
}

template<class T> void StackT<T>::Push(const T& element)
{
    
    StackElement* pSE = new StackElement;
    pSE->element = element;
    pSE->next = _stackBase;
    _stackBase = pSE;
    
    return;
}

template<class T> bool StackT<T>::Pop(T& element)
{

    if ( _stackBase )
    {
	StackElement *pSE = _stackBase;
	element = pSE->element;
	_stackBase = _stackBase->next;
	delete pSE;
	return true;
    }
    else
    {
	return false;
    }
}

template<class T> T* StackT<T>::getTop() const
{
    if ( _stackBase )
    {
	return &(_stackBase->element);
    }
    else
    {
	return (0);
    }
}

template<class T> int StackT<T>::Size() const
{
    int size = 0;
    
    StackElement* pElement = _stackBase;
    while (pElement)
    {
	pElement = pElement->next;	    
	size++;
    }
    return size;
}

template<class T> StackT<T>& StackT<T>::operator=(const StackT<T>& x)
{
    Empty();
    
    for ( int i = x.Size() ; i > 0 ; i-- )
    {
	StackElement* pElement = x._stackBase;
	int j = 1;
	
	while (j < i )
	{
	    pElement = pElement->next;
	    j++;
	}
	Push(pElement->element);
    }
    return (*this);
}

#endif
