text: #pragma once
  
  #include "Mint/MTLibrary/MemoryTrace.h"
  #include "Mint/Log.h"
  
  namespace Mint {
  
  	template<class DATA_TYPE>
  	struct TDNode :DATA_TYPE
  	{
  		unsigned int		NodeNumber;
  		TDNode<DATA_TYPE>* pPrev;
  		TDNode<DATA_TYPE>* pNext;
  	};
  
  	template<class DATA_TYPE>
  	class TDoublyList
  	{
  	public:
  		TDNode<DATA_TYPE>* pHeadNode;
  		TDNode<DATA_TYPE>* pTailNode;
  		unsigned int		NodeUseCount;
  		unsigned int		NodeLinkCount;
  
  		TDNode<DATA_TYPE>* pFreeList;
  		unsigned int		FreeListCount;
  
  		void Create()
  		{
  			pHeadNode = nullptr;
  			pTailNode = nullptr;
  			NodeUseCount = 0;
  			NodeLinkCount = 0;
  
  			pFreeList = nullptr;
  			FreeListCount = 0;
  		}
  
  		void Release()
  		{
  
  			TDNode<DATA_TYPE>* node = pHeadNode, * del_node = nullptr;
  			while (node)
  			{
  				del_node = node;
  				node = node->pNext;
  				MY_DELETE(del_node);
  			}
  
  			node = pFreeList;
  			while (node)
  			{
  				del_node = node;
  				node = node->pNext;
  				MY_DELETE(del_node);
  			}
  			Create();
  		}
  
  		TDNode<DATA_TYPE>* GetNode()
  		{
  			TDNode<DATA_TYPE>* node = nullptr;
  			if (FreeListCount > 0)
  			{
  				node = pFreeList;
  				pFreeList = pFreeList->pNext;
  				--FreeListCount;
  			}
  			else
  			{
  				MY_NEW(node, TDNode<DATA_TYPE>);
  				ZeroMemory(node, sizeof(TDNode< DATA_TYPE >));
  			}
  
  			node->NodeNumber = 0;
  			node->pNext = nullptr;
  			node->pPrev = nullptr;
  
  			++NodeUseCount;
  			return node;
  		}
  
  		void ReleaseNodeEx(TDNode<DATA_TYPE>*& release_node)
  		{
  			if (!release_node)
  			{
  				MT_CORE_ERROR("TDoublyList< {0} >::ReleaseNodeEx   error : release_node = nullptr", typeid(DATA_TYPE).name());
  				return;
  			}
  			if (NodeUseCount == 0)
  			{
  				MT_CORE_ERROR("TDoublyList< {0} >::ReleaseNodeEx   error : NodeUseCount = 0", typeid(DATA_TYPE).name());
  				return;
  			}
  
  			MY_DELETE(release_node);
  			--NodeUseCount;
  		}
  
  		void ReleaseNode(TDNode<DATA_TYPE>*& release_node)
  		{
  			if (!release_node)
  			{
  				MT_CORE_ERROR("DoublyList::ReleaseNode   error : release_node = nullptr");
  				return;
  			}
  			if (NodeUseCount == 0)
  			{
  				MT_CORE_ERROR("DoublyList::ReleaseNode   error : NodeUseCount = 0");
  				return;
  			}
  
  
  			ZeroMemory(release_node, sizeof(TDNode<DATA_TYPE>));
  
  			if (FreeListCount > 0)
  				release_node->pNext = pFreeList;
  			pFreeList = release_node;
  			release_node = nullptr;
  			++FreeListCount;
  			--NodeUseCount;
  		}
  
  		void Link(TDNode<DATA_TYPE>* node)
  		{
  			if (!node)
  			{
  				MT_CORE_ERROR("TDoublyList< {0} >::Link   link node = nullptr", typeid(DATA_TYPE).name());
  				return;
  			}
  
  			node->pNext = nullptr;
  			node->pPrev = nullptr;
  
  			if (!pHeadNode)
  			{
  				pHeadNode = pTailNode = node;
  			}
  			else
  			{
  				pTailNode->pNext = node;
  				node->pPrev = pTailNode;
  				pTailNode = node;
  			}
  			++NodeLinkCount;
  		}
  
  		void LinkToHead(TDNode<DATA_TYPE>* node)
  		{
  			if (!node)
  			{
  				Debug::Log("TDoublyList< {0} >::LinkToHead   link node = nullptr", typeid(DATA_TYPE).name());
  				return;
  			}
  
  			node->pPrev = nullptr;
  			node->pNext = nullptr;
  
  			if (!pHeadNode)
  			{
  				pHeadNode = pTailNode = node;
  			}
  			else
  			{
  				pHeadNode->pPrev = node;
  				node->pNext = pHeadNode;
  				pHeadNode = node;
  			}
  			++NodeLinkCount;
  		}
  
  		void LinkInsertPrev(TDNode<DATA_TYPE>* dest_node, TDNode<DATA_TYPE>* new_node)
  		{
  			if (!new_node)
  			{
  				MT_CORE_ERROR("TDoublyList<{0}>::LinkInsertPrev   new_node = nullptr", typeid(DATA_TYPE).name);
  				return;
  			}
  
  			if (dest_node)
  			{
  				new_node->pPrev = dest_node->pPrev;
  				new_node->pNext = dest_node;
  				if (new_node->pPrev)
  					new_node->pPrev->pNext = new_node;
  				else
  					pHeadNode = new_node;
  				dest_node->pPrev = new_node;
  			}
  			else
  			{
  				MT_CORE_ERROR("TDoublyList<{0}>::LinkInsertPrev   dest_node = nullptr", typeid(DATA_TYPE).name);
  				return;
  			}
  			++NodeLinkCount;
  		}
  
  		void LinkInsertNext(TDNode<DATA_TYPE>* dest_node, TDNode<DATA_TYPE>* new_node)
  		{
  			if (!new_node)
  			{
  				MT_CORE_ERROR("TDoublyList<{0}>::LinkInsertNext   new_node = nullptr", typeid(DATA_TYPE).name);
  				return;
  			}
  
  			if (dest_node)
  			{
  				new_node->pNext = dest_node->pNext;
  				new_node->pPrev = dest_node;
  				if (new_node->pNext)
  					new_node->pNext->pPrev = new_node;
  				else
  					pTailNode = new_node;
  				dest_node->pNext = new_node;
  			}
  			else
  			{
  				MT_CORE_ERROR("TDoublyList<{0}>::LinkInsertNext   dest_node = nullptr", typeid(DATA_TYPE).name);
  				return;
  			}
  			++NodeLinkCount;
  		}
  
  		bool LinkInsertOrderWithNumber(TDNode<DATA_TYPE>* new_node)
  		{
  			if (!new_node)
  			{
  				MT_CORE_ERROR("TDoublyList<{0}>::LinkInsertOrderWithNumber   new_node = nullptr", typeid(DATA_TYPE).name);
  				return false;
  			}
  
  			if (!pHeadNode)
  			{
  				Link(new_node);
  				return true;
  			}
  
  			bool flag = false;
  			TDNode<DATA_TYPE>* prev_node = nullptr;
  			TDNode<DATA_TYPE>* node = pHeadNode;
  			while (node)
  			{
  				if (new_node->NodeNumber >= node->NodeNumber)
  				{
  					if (node->pNext == nullptr)
  					{
  						flag = true;
  						Link(new_node);
  						break;
  					}
  				}
  				else
  				{
  					flag = true;
  					LinkInsertPrev(node, new_node);
  					break;
  				}
  				node = node->pNext;
  			}
  			return flag;
  		}
  
  		bool Unlink(TDNode<DATA_TYPE>* node)
  		{
  			if (!node)
  			{
  				MT_CORE_ERROR("TDoublyList< {0} >::Unlink   error : unlink node = nullptr", typeid(DATA_TYPE).name());
  				return false;
  			}
  
  			if (node->pPrev)
  			{
  				if (node->pNext)
  				{
  					node->pPrev->pNext = node->pNext;
  					node->pNext->pPrev = node->pPrev;
  				}
  				else if (pTailNode == node)
  				{
  					pTailNode = pTailNode->pPrev;
  					pTailNode->pNext = nullptr;
  				}
  				else
  				{
  					MT_CORE_ERROR("TDoublyList< {0} >::Unlink   if( pTailNode != node ) it will lose the node.", typeid(DATA_TYPE).name());
  					return false;
  				}
  			}
  			else if (pHeadNode == node)
  			{
  				if (node->pNext)
  				{
  					pHeadNode = pHeadNode->pNext;
  					pHeadNode->pPrev = nullptr;
  				}
  				else
  				{
  					pHeadNode = nullptr;
  					pTailNode = nullptr;
  				}
  			}
  			else
  			{
  				MT_CORE_ERROR("TDoublyList< {0} >::Unlink   if( pHeadNode != node ) it will lose the node.", typeid(DATA_TYPE).name());
  				return FALSE;
  			}
  
  			node->pNext = nullptr;
  			node->pPrev = nullptr;
  
  			if (NodeLinkCount > 0)
  				--NodeLinkCount;
  			else
  				MT_CORE_ERROR("TDoublyList< {0} >::Unlink   error : NodeLinkCount = 0", typeid(DATA_TYPE).name());
  			return TRUE;
  		}
  
  		TDNode<DATA_TYPE>* SearchNodeWithNumber(unsigned int node_number)
  		{
  			TDNode<DATA_TYPE>* node = nullptr;
  			while (node)
  			{
  				if (node->NodeNumber == node_number)
  					return node;
  				node = node->pNext;
  			}
  			return nullptr;
  		}
  
  	};
  }