
// This is for simple but very convenient doubly linked lists..
// You need a LTLink for the list head, and this just defines
// really common routines to insert, remove, and tie off.

#ifndef __LTLINK_H__
#define __LTLINK_H__


	class LTLink;


	#include "ltbasetypes.h"


	// This goes thru and C++ deletes everything in a list.
	// You need a LTLink *pCur, *pNext;
	#define CPP_DELETELIST(_list_pointer, type) \
	{\
		pCur = (_list_pointer)->m_Head.m_pNext;\
		while(pCur != &(_list_pointer)->m_Head)\
		{\
			pNext = pCur->m_pNext;\
			delete ((type*)pCur->m_pData);\
			pCur = pNext;\
		}\
		dl_InitList(_list_pointer);\
	}


	// Use these to declare blank LTLinks and LTLists.
	#define DECLARE_LTLINK(name) \
		LTLink name(LTLink_Init);

	#define DECLARE_LTLIST(name) \
		LTList name(LTLink_Init);


	typedef enum
	{
		LTLink_Init=0
	} LTLinkCommand;



	// Use LTLink whenever you need m_pData but you can use this if you have a list head.
	class CheapLTLink
	{
	public:
		
		void		Init();
		void		Term();
		void		Remove();
		void		TieOff();
		void		AddAfter(CheapLTLink *pLink);
		void		AddBefore(CheapLTLink *pLink);
		LTLink*		operator[](unsigned long i);
		inline LTLink*		AsDLink()	{return (LTLink*)this;}
		inline LTLink*		AsLTLink()	{return (LTLink*)this;}
		LTBOOL		IsTiedOff();

	public:

		LTLink	*m_pPrev, *m_pNext;
	};


	class LTLink : public CheapLTLink
	{
	public:

		inline	LTLink() {}
		inline	LTLink(LTLinkCommand cmd)
		{
			TieOff();
		}

		inline void	Init2(void *pData)
		{
			TieOff();
			m_pData = pData;
		}


	public:
		void	*m_pData;
	};


	inline void CheapLTLink::Init()
	{
		TieOff();
	}

	inline void CheapLTLink::Term()
	{
		Remove();
	}

	inline void CheapLTLink::Remove()
	{
		m_pPrev->m_pNext = m_pNext;
		m_pNext->m_pPrev = m_pPrev;
		TieOff();
	}

	inline void CheapLTLink::TieOff()
	{
		m_pPrev = m_pNext = (LTLink*)this;
	}

	inline void CheapLTLink::AddAfter(CheapLTLink *pLink)
	{
		pLink->m_pPrev = (LTLink*)this;
		pLink->m_pNext = m_pNext;
		pLink->m_pPrev->m_pNext = pLink->m_pNext->m_pPrev = (LTLink*)pLink;
	}

	inline void	CheapLTLink::AddBefore(CheapLTLink *pLink)
	{
		pLink->m_pPrev = m_pPrev;
		pLink->m_pNext = (LTLink*)this;
		pLink->m_pPrev->m_pNext = pLink->m_pNext->m_pPrev = (LTLink*)pLink;
	}

	// Makes it easy to traverse the list in either direction.
	inline LTLink* CheapLTLink::operator[](unsigned long i)
	{
		return ((LTLink**)this)[i];
	}

	inline LTBOOL CheapLTLink::IsTiedOff()
	{
		return m_pPrev == this && m_pNext == this;
	}


	inline void dl_TieOff(CheapLTLink *pLink)
	{
		pLink->TieOff();
	}

	inline void dl_Insert(CheapLTLink *pAfter, CheapLTLink *pLink)
	{
		pAfter->AddAfter(pLink);
	}

	inline void dl_Remove(CheapLTLink *pLink)
	{
		pLink->Remove();
	}


	// You can use this list structure to wrap up a linked list
	// if you want to keep a count of the elements.
	class LTList
	{
	public:

						LTList()
						{
							m_Head.TieOff();
							m_nElements = 0;
						}
						
						LTList(LTLinkCommand cmd)
						{
							m_Head.TieOff();
							m_nElements = 0;
						}

		unsigned long	m_nElements;
		LTLink			m_Head;
	};

	inline void dl_InitList(LTList *pList)
	{
		dl_TieOff(&pList->m_Head);
		pList->m_nElements = 0;
	}

	inline void dl_AddAfter(LTList *pList, LTLink *pAfter, LTLink *pLink, void *pObj)
	{
		pLink->m_pData = pObj;
		dl_Insert(pAfter, pLink);
		++pList->m_nElements;
	}

	inline void dl_AddBefore(LTList *pList, LTLink *pBefore, LTLink *pLink, void *pObj)
	{
		dl_AddAfter(pList, pBefore->m_pPrev, pLink, pObj);
	}

	inline void dl_AddHead(LTList *pList, LTLink *pLink, void *pObj)
	{
		dl_AddAfter(pList, &pList->m_Head, pLink, pObj);
	}

	inline void dl_AddTail(LTList *pList, LTLink *pLink, void *pObj)
	{
		dl_AddAfter(pList, pList->m_Head.m_pPrev, pLink, pObj);
	}

	inline void dl_RemoveAt(LTList *pList, LTLink *pLink)
	{
		dl_Remove(pLink);
		--pList->m_nElements;
	}


#endif  // __LTLINK_H__
