// -----------------------------------------------------------------------------
// -- Header file ISTACKLIST.H 	indirect stack list container                 --
// -- Writed by David Rouchet                                                 --
// -----------------------------------------------------------------------------

#ifndef __ISTACKLIST_H
#define __ISTACKLIST_H

#include <windows.h>
// Si cette classe doit être utilisée en multithreading
// Il est recommandé d'enlever la mise en commentaire
// de la ligne ci-dessous.

//#define __USECRITICALSECTION

// -----------------------------------------------------------------------------
// ---------------- Declaration Class StackNode --------------------------------
// -----------------------------------------------------------------------------

template <class T> class StackNode
{
 public :

	StackNode   *Previous;
	StackNode   *Next;
	T		    *lpObject;

	StackNode();
	StackNode(T* lpObject);

};

// -----------------------------------------------------------------------------
// ---------------- Declaration Class MIStackList ----------------------------
// -----------------------------------------------------------------------------

template <class T> class MIStackList
{
 public :

 private :

#ifdef __USECRITICALSECTION
    CRITICAL_SECTION        CriticalSection;
#endif

	StackNode<T>	*Head;
	StackNode<T>	*Tail;

	DWORD	NumberOfObject;

 public :


	MIStackList();
	~MIStackList();

	BOOL    Push(T* Object);
	T*		Pop();

	DWORD	GetItemsInContainer(){return NumberOfObject;}
    void    FreeAllObject();
};

// -----------------------------------------------------------------------------
// ---------------- Definition Class MIStackListIterator ---------------------
// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// ---------------- Definition Class MIStackList -----------------------------
// -----------------------------------------------------------------------------

template <class T>
MIStackList<T>::MIStackList()
{
#ifdef __USECRITICALSECTION
    ::InitializeCriticalSection(&CriticalSection);
#endif

	Tail = Head = NULL;
	NumberOfObject = 0;
}

template <class T>
MIStackList<T>::~MIStackList()
{
#ifdef __USECRITICALSECTION
    ::DeleteCriticalSection(&CriticalSection);
#endif

	StackNode<T> *NodeToDelete;

	if (NumberOfObject != 0) {
        NodeToDelete = Head;
		while (NodeToDelete != NULL) {
            Head = NodeToDelete->Next;
            delete NodeToDelete;
			NodeToDelete = Head;
            NumberOfObject--;
		}
	}
}

template <class T>
BOOL MIStackList<T>::Push(T* NewObject)
{
    BOOL    bSuccess = FALSE;

#ifdef __USECRITICALSECTION
    ::EnterCriticalSection(&CriticalSection);
#endif

	if (NewObject != NULL) {
		StackNode<T> *NewNode = new StackNode<T>(NewObject);
		if (NewNode != NULL) {
            if (Head == NULL) { // Tail est aussi NULL dans ce cas
                Head  = Tail = NewNode;
            } else {
                NewNode->Next   = Head;
                Head->Previous  = NewNode;
                Head = NewNode;
            }
			NumberOfObject++;
            bSuccess = TRUE;
		}
	 }

#ifdef __USECRITICALSECTION
        ::LeaveCriticalSection(&CriticalSection);
#endif
	 return bSuccess;
}

template <class T>
T* MIStackList<T>::Pop()
{

    T               *lpObject = NULL;
    StackNode<T>    *PreviousNode;

#ifdef __USECRITICALSECTION
    ::EnterCriticalSection(&CriticalSection);
#endif


	if (Tail != NULL) { // Dans ce cas Head l'est aussi
        PreviousNode = Tail->Previous;
        if (PreviousNode) {
            PreviousNode->Next = NULL;
            lpObject = Tail->lpObject;
            delete Tail;
            Tail = PreviousNode;
        } else { // Si le noeud précédent est null alors Tail == Head
            lpObject = Tail->lpObject;
            delete Tail;
            Tail = Head = NULL;
        }
	    NumberOfObject--;
	 }

#ifdef __USECRITICALSECTION
        ::LeaveCriticalSection(&CriticalSection);
#endif
	 return lpObject;
}


template <class T>
void MIStackList<T>::FreeAllObject()
{
#ifdef __USECRITICALSECTION
    ::EnterCriticalSection(&CriticalSection);
#endif

	StackNode<T> *NodeToDelete;

	if (NumberOfObject != 0) {
        NodeToDelete = Head;
		while (NodeToDelete != NULL) {
            if (NodeToDelete->lpObject) delete NodeToDelete->lpObject; 
            Head = NodeToDelete->Next;
            delete NodeToDelete;
			NodeToDelete = Head;
            NumberOfObject--;
		}
	}

	Tail = Head = NULL;
	NumberOfObject = 0;

#ifdef __USECRITICALSECTION
    ::LeaveCriticalSection(&CriticalSection);
#endif
}

// -----------------------------------------------------------------------------
// ---------------- Definition Class StackNode ---------------------------------
// -----------------------------------------------------------------------------


template <class T>
StackNode<T>::StackNode()
{
	lpObject 	= NULL;
	Previous	= NULL;
	Next		= NULL;
}

template <class T>
StackNode<T>::StackNode(T* lpobject)
{
	lpObject 	= lpobject;
	Previous	= NULL;
	Next		= NULL;
}

#endif


