/* Copyright (c) <2003-2019> <Newton Game Dynamics>
* 
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* 
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/


#ifndef __D_MAP__
#define __D_MAP__

template<class OBJECT, class KEY>
class dMap
{
	public:
	class dTreeNode
	{
		enum REDBLACK_COLOR
		{
			RED = true,
			BLACK = false
		};

		dTreeNode (const KEY &key, dTreeNode* parentNode)
			:m_info()
			,m_key(key)
			,m_left(nullptr)
			,m_right(nullptr)
			,m_parent(parentNode)
			,m_color(false)
			,m_inTree(false)
		{
			SetColor(RED);
			SetInTreeFlag(true);
		}
	
		dTreeNode (const OBJECT &info, const KEY &key, dTreeNode* parentNode)
			:m_info(info)
			,m_key(key)
			,m_left(nullptr)
			,m_right(nullptr)
			,m_parent(parentNode)
			,m_color(false)
			,m_inTree(false)
		{
			SetColor(RED);
			SetInTreeFlag(true);
		}

		virtual ~dTreeNode () 
		{
		}

		void SetInTreeFlag(bool flag)
		{
			m_inTree = flag;
		}

		bool GetColor() const
		{
			return m_color;
		}

		void SetColor(bool color)
		{
			m_color = color;
		}

		dTreeNode& operator= (dTreeNode& src)
		{
			dAssert (0);
			return* this;
		}

		dTreeNode* GetLeft () const
		{
			return m_left;
		}

		dTreeNode* GetRight () const
		{
			return m_right;
		}

		dTreeNode* GetParent ()
		{
			return m_parent;
		}

		void SetLeft (dTreeNode* const node)
		{
			m_left = node;
		}

		void SetRight (dTreeNode* const node)
		{
			m_right = node;
		}

		void SetParent (dTreeNode* const node)
		{
			m_parent = node;
		}

		public:
		const KEY& GetKey() const
		{
			return m_key;
		}

		OBJECT& GetInfo()
		{
			return m_info;
		}

		dTreeNode* Minimum() const
		{
			dTreeNode* ptr = (dTreeNode*)this;
			for (; ptr->m_left; ptr = ptr->m_left);
			return ptr;
		}

		dTreeNode* Next() const
		{
			if (m_right) {
				return m_right->Minimum();
			}

			dTreeNode* node = (dTreeNode*)this;
			dTreeNode* ptr = m_parent;
			for (; ptr && node == ptr->m_right; ptr = ptr->m_parent) {
				node = ptr;
			}
			return ptr;
		}

		void Unlink(dTreeNode** const head)
		{
			dTreeNode* const node = this;
			node->SetInTreeFlag(false);

			if (!node->m_left || !node->m_right) {
				// y has a nullptr node as a child 
				dTreeNode* const endNode = node;

				// x is y's only child 
				dTreeNode* child = endNode->m_right;
				if (endNode->m_left) {
					child = endNode->m_left;
				}

				// remove y from the parent chain 
				if (child) {
					child->m_parent = endNode->m_parent;
				}

				if (endNode->m_parent) {
					if (endNode == endNode->m_parent->m_left) {
						endNode->m_parent->m_left = child;
					} else {
						endNode->m_parent->m_right = child;
					}
				} else {
					*head = child;
				}

				if (endNode->GetColor() == BLACK) {
					endNode->m_parent->RemoveFixup(child, head);
				}
			} else {

				// find tree successor with a nullptr node as a child 
				dTreeNode* endNode = node->m_right;
				while (endNode->m_left != nullptr) {
					endNode = endNode->m_left;
				}

				// x is y's only child 
				dTreeNode* const child = endNode->m_right;

				endNode->m_left = node->m_left;
				node->m_left->m_parent = endNode;

				dTreeNode* endNodeParent = endNode;
				if (endNode != node->m_right) {
					if (child) {
						child->m_parent = endNode->m_parent;
					}
					endNode->m_parent->m_left = child;
					endNode->m_right = node->m_right;
					node->m_right->m_parent = endNode;
					endNodeParent = endNode->m_parent;
				}


				if (node == *head) {
					*head = endNode;
				} else if (node == node->m_parent->m_left) {
					node->m_parent->m_left = endNode;
				} else {
					node->m_parent->m_right = endNode;
				}
				endNode->m_parent = node->m_parent;

				bool oldColor = endNode->GetColor();
				endNode->SetColor(node->GetColor());
				node->SetColor(oldColor);

				if (oldColor == BLACK) {
					endNodeParent->RemoveFixup(child, head);
				}
			}
		}

		void RotateLeft(dTreeNode** const head)
		{
			dTreeNode* const me = this;
			dTreeNode* const child = me->m_right;

			//dAssert(child);
			me->m_right = child->m_left;
			if (child->m_left != nullptr) {
				child->m_left->m_parent = me;
			}

			if (child != nullptr) {
				child->m_parent = me->m_parent;
			}
			if (me->m_parent) {
				if (me == me->m_parent->m_left) {
					me->m_parent->m_left = child;
				} else {
					me->m_parent->m_right = child;
				}
			} else {
				*head = child;
			}

			// link child and me 
			child->m_left = me;
			if (me != nullptr) {
				me->m_parent = child;
			}
		}

		// rotate node me to right  *
		void RotateRight(dTreeNode** const head)
		{
			dTreeNode* const me = this;
			dTreeNode* const child = me->m_left;

			//dAssert(child);
			me->m_left = child->m_right;
			if (child->m_right != nullptr) {
				child->m_right->m_parent = me;
			}

			// establish child->m_parent link 
			if (child != nullptr) {
				child->m_parent = me->m_parent;
			}
			if (me->m_parent) {
				if (me == me->m_parent->m_right) {
					me->m_parent->m_right = child;
				} else {
					me->m_parent->m_left = child;
				}
			} else {
				*head = child;
			}

			// link me and child 
			child->m_right = me;
			if (me != nullptr) {
				me->m_parent = child;
			}
		}

		void RemoveFixup(dTreeNode* const me, dTreeNode** const head)
		{
			dTreeNode* ptr = this;
			dTreeNode* node = me;
			while ((node != *head) && (!node || node->GetColor() == BLACK)) {
				if (node == ptr->m_left) {
					if (!ptr) {
						return;
					}
					dTreeNode* tmp = ptr->m_right;
					if (!tmp) {
						return;
					}
					if (tmp->GetColor() == RED) {
						tmp->SetColor(BLACK);
						ptr->SetColor(RED);
						ptr->RotateLeft(head);
						tmp = ptr->m_right;
						if (!tmp) {
							return;
						}
					}
					if ((!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) &&
						(!tmp->m_right || (tmp->m_right->GetColor() == BLACK))) {
						tmp->SetColor(RED);
						node = ptr;
						ptr = ptr->m_parent;
						continue;
					} else if (!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) {
						tmp->m_left->SetColor(BLACK);
						tmp->SetColor(RED);
						tmp->RotateRight(head);
						tmp = ptr->m_right;
						//if (!ptr || !tmp) {
						if (!tmp) {
							return;
						}
					}
					tmp->SetColor(ptr->GetColor());
					if (tmp->m_right) {
						tmp->m_right->SetColor(BLACK);
					}
					if (ptr) {
						ptr->SetColor(BLACK);
						ptr->RotateLeft(head);
					}
					node = *head;

				} else {
					if (!ptr) {
						return;
					}
					dTreeNode* tmp = ptr->m_left;
					if (!tmp) {
						return;
					}
					if (tmp->GetColor() == RED) {
						tmp->SetColor(BLACK);
						ptr->SetColor(RED);
						ptr->RotateRight(head);
						tmp = ptr->m_left;
						if (!tmp) {
							return;
						}
					}

					if ((!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) &&
						(!tmp->m_left || (tmp->m_left->GetColor() == BLACK))) {
						tmp->SetColor(RED);
						node = ptr;
						ptr = ptr->m_parent;
						continue;
					} else if (!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) {
						tmp->m_right->SetColor(BLACK);
						tmp->SetColor(RED);
						tmp->RotateLeft(head);
						tmp = ptr->m_left;
						//if (!ptr || !tmp) {
						if (!tmp) {
							return;
						}
					}
					tmp->SetColor(ptr->GetColor());
					if (tmp->m_left) {
						tmp->m_left->SetColor(BLACK);
					}
					if (ptr) {
						ptr->SetColor(BLACK);
						ptr->RotateRight(head);
					}
					node = *head;
				}
			}
			if (node) {
				node->SetColor(BLACK);
			}
		}

		void InsertFixup(dTreeNode** const head)
		{
			dTreeNode* ptr = this;
			// check Red-Black properties 
			//dAssert((ptr == *head) || ptr->m_parent);
			while ((ptr != *head) && (ptr->m_parent->GetColor() == RED)) {
				// we have a violation 
				//dAssert(ptr->m_parent);
				//dAssert(ptr->m_parent->m_parent);
				if (ptr->m_parent == ptr->m_parent->m_parent->m_left) {
					dTreeNode* const tmp = ptr->m_parent->m_parent->m_right;
					if (tmp && (tmp->GetColor() == RED)) {
						// uncle is RED 
						ptr->m_parent->SetColor(BLACK);
						tmp->SetColor(BLACK);
						ptr->m_parent->m_parent->SetColor(RED);
						ptr = ptr->m_parent->m_parent;
					} else {
						// uncle is BLACK 
						if (ptr == ptr->m_parent->m_right) {
							// make ptr a left child 
							ptr = ptr->m_parent;
							ptr->RotateLeft(head);
						}

						ptr->m_parent->SetColor(BLACK);
						if (ptr->m_parent->m_parent) {
							ptr->m_parent->m_parent->SetColor(RED);
							ptr->m_parent->m_parent->RotateRight(head);
						}
					}
				} else {
					//dAssert (ptr->m_parent == ptr->m_parent->m_parent->m_right);
					// mirror image of above code 
					dTreeNode* const tmp = ptr->m_parent->m_parent->m_left;
					if (tmp && (tmp->GetColor() == RED)) {
						//uncle is RED 
						ptr->m_parent->SetColor(BLACK);
						tmp->SetColor(BLACK);
						ptr->m_parent->m_parent->SetColor(RED);
						ptr = ptr->m_parent->m_parent;
					} else {
						// uncle is BLACK 
						if (ptr == ptr->m_parent->m_left) {
							ptr = ptr->m_parent;
							ptr->RotateRight(head);
						}
						ptr->m_parent->SetColor(BLACK);
						if (ptr->m_parent->m_parent->GetColor() == BLACK) {
							ptr->m_parent->m_parent->SetColor(RED);
							ptr->m_parent->m_parent->RotateLeft(head);
						}
					}
				}
			}
			(*head)->SetColor(BLACK);
		}


		private:
		OBJECT m_info;
		KEY m_key; 
		dTreeNode* m_left;
		dTreeNode* m_right;
		dTreeNode* m_parent;
		bool m_color;
		bool m_inTree;
		friend class dMap<OBJECT, KEY>;
	};

	class Iterator
	{
		public:
		Iterator(const dMap<OBJECT,KEY> &me)
		{
			m_ptr = nullptr;
			m_tree = &me;
		}

		~Iterator()
		{
		}

		void Begin() 
		{
			m_ptr = m_tree->Minimum();
		}

		void End()  
		{
			m_ptr = m_tree->Maximum();
		}

		void Set (dTreeNode* const node)
		{
			m_ptr = node;
		}

		operator int() const 
		{
			return m_ptr != nullptr;
		}

		void operator++ ()
		{
			//dAssert (m_ptr);
			m_ptr = m_ptr->Next();
		}

		void operator++ (int)
		{
			//dAssert (m_ptr);
			m_ptr = m_ptr->Next();
		}

		void operator-- () 
		{
			//dAssert (m_ptr);
			m_ptr = m_ptr->Prev();
		}

		void operator-- (int) 
		{
			//dAssert (m_ptr);
			m_ptr = m_ptr->Prev();
		}

		OBJECT &operator* () const 
		{
			return ((dTreeNode*)m_ptr)->GetInfo();
		}

		dTreeNode* GetNode() const
		{
			return (dTreeNode*)m_ptr;
		}

		KEY GetKey () const
		{
			dTreeNode* const tmp = (dTreeNode*)m_ptr;
			return tmp ? tmp->GetKey() : KEY(0);
		}

		private:
		dTreeNode* m_ptr;
		const dMap* m_tree;
	};


	// ***********************************************************
	// member functions
	// ***********************************************************
	public:
	dMap ();
	virtual ~dMap (); 

	operator int() const;
	int GetCount() const;

	dTreeNode* GetRoot () const;
	dTreeNode* Minimum () const;
	dTreeNode* Maximum () const;

	dTreeNode* Find (KEY key) const;
	dTreeNode* FindGreater (KEY key) const;
	dTreeNode* FindGreaterEqual (KEY key) const;
	dTreeNode* FindLessEqual (KEY key) const;

	dTreeNode* GetNodeFromInfo (OBJECT &info) const;

	dTreeNode* Insert (KEY key);
	dTreeNode* Insert (const OBJECT &element, KEY key);
	dTreeNode* Insert (const OBJECT &element, KEY key, bool& elementWasInTree);
	dTreeNode* Insert (dTreeNode* const node, KEY key);

	dTreeNode* Replace (OBJECT &element, KEY key);
	dTreeNode* ReplaceKey (KEY oldKey, KEY newKey);
	dTreeNode* ReplaceKey (dTreeNode* const node, KEY key);

	void Unlink (dTreeNode* const node);

	void Remove (KEY key);
	void Remove (dTreeNode* const node);
	void RemoveAll (); 

	bool SanityCheck () const;


	// ***********************************************************
	// member variables
	// ***********************************************************
	private:
	void RemoveAllLow (dTreeNode* const root);
	int CompareKeys (const KEY &key0, const KEY &key1) const;
	bool SanityCheck (dTreeNode* const ptr, int height) const;

	int m_count;
	dTreeNode* m_head;
	friend class dTreeNode;
};

template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::dMap ()
{
	m_count	= 0;
	m_head = nullptr;
}

template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::~dMap () 
{
	RemoveAll();
}


template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::operator int() const
{
	return m_head != nullptr;
}

template<class OBJECT, class KEY>
int dMap<OBJECT, KEY>::GetCount() const
{
	return m_count;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Minimum () const
{
	return m_head ? (dTreeNode*) m_head->Minimum() : nullptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Maximum () const
{
	return m_head ? (dTreeNode*) m_head->Maximum() : nullptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::GetRoot () const
{
	return m_head;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Find (KEY key) const
{
	if (m_head == nullptr) {
		return nullptr;
	}

	dTreeNode* ptr = m_head;
	while (ptr != nullptr) {
		int val = CompareKeys (ptr->m_key, key);
		if (!val) {
			break;
		}
		if (val < 0) {
			ptr = ptr->GetLeft();
		} else {
			ptr = ptr->GetRight();
		}
	}
	return ptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::GetNodeFromInfo (OBJECT &info) const
{
	dTreeNode* node = (dTreeNode*) &info;
	int offset = ((char*) &node->m_info) - ((char *) node);
	node = (dTreeNode*) (((char *) node) - offset);

//	dAssert (node->IsInTree ());
	dAssert (&node->GetInfo () == &info);
	return (node->IsInTree ()) ? node : nullptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindGreater (KEY key) const
{
	if (m_head == nullptr) {
		return nullptr;
	}

	dTreeNode* prev = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	while (ptr != nullptr) {
		val = CompareKeys (ptr->m_key, key);
		if (!val) {
			return (dTreeNode*) ptr->Next();
		}
		prev = ptr;
		if (val < 0) {
			ptr = ptr->GetLeft();
		} else {
			ptr = ptr->GetRight();
		}
	}

	if (val > 0) {
		while (prev->m_parent && (prev->m_parent->m_right == prev)) {
			prev = prev->GetParent(); 
		}
		prev = prev->GetParent(); 
	}
	return (dTreeNode*) prev; 
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindGreaterEqual (KEY key) const
{
	if (m_head == nullptr) {
		return nullptr;
	}

	dTreeNode* prev = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	while (ptr != nullptr) {
		val = CompareKeys (ptr->m_key, key);
		if (!val) {
			return ptr;
		}
		prev = ptr;
		if (val < 0) {
			ptr = ptr->GetLeft();
		} else {
			ptr = ptr->GetRight();
		}
	}

	if (val > 0) {
		while (prev->m_parent && (prev->m_parent->m_right == prev)) {
			prev = prev->GetParent(); 
		}
		prev = prev->GetParent(); 
	}
	return (dTreeNode*) prev; 
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindLessEqual (KEY key) const
{
	if (m_head == nullptr) {
		return nullptr;
	}

	dTreeNode* prev = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	while (ptr != nullptr) {
		val = CompareKeys (ptr->m_key, key);
		if (!val) {
			return ptr;
		}
		prev = ptr;
		if (val < 0) {
			ptr = ptr->GetLeft();
		} else {
			ptr = ptr->GetRight();
		}
	}

	if (val < 0) {
		while (prev->m_parent && (prev->m_parent->m_left == prev)) {
			prev = prev->GetParent(); 
		}
		prev = prev->GetParent(); 
	}
	return (dTreeNode*) prev; 
}


template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (KEY key)
{
	dTreeNode* parent = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	while (ptr != nullptr) {
		parent = ptr;
		val = CompareKeys (ptr->m_key, key);

		if (val < 0) {
			ptr = ptr->GetLeft();
		} else if (val > 0) {
			ptr = ptr->GetRight();
		} else {
			return ptr;
		}
	}
	m_count	++;

	ptr = new dTreeNode (key, parent);
	if (!parent) {
		m_head = ptr;
	} else {
		if (val < 0) {
			parent->m_left = ptr; 
		} else {
			parent->m_right = ptr;
		}
	}
	ptr->InsertFixup ((dTreeNode**)&m_head);
	return ptr;
}


template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (const OBJECT &element, KEY key, bool& elementWasInTree)
{
	dTreeNode* parent = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	elementWasInTree = false;
	while (ptr != nullptr) {
		parent = ptr;
		val = CompareKeys (ptr->m_key, key);

		if (val < 0) {
			ptr = ptr->GetLeft();
		} else if (val > 0) {
			ptr = ptr->GetRight();
		} else {
			elementWasInTree = true;
			return ptr;
		}
	}
	m_count	++;

	ptr = new dTreeNode (element, key, parent);
	if (!parent) {
		m_head = ptr;
	} else {
		if (val < 0) {
			parent->m_left = ptr; 
		} else {
			parent->m_right = ptr;
		}
	}
	ptr->InsertFixup ((dTreeNode**)&m_head);
	return ptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (const OBJECT &element, KEY key)
{
	bool foundState;
	dTreeNode* node = Insert (element, key, foundState);
	if (foundState) {
		node = nullptr;
	}
	return node;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (typename dMap<OBJECT, KEY>::dTreeNode* const node, KEY key)
{
	int val = 0;
	dTreeNode* ptr = m_head;
	dTreeNode* parent = nullptr;
	while (ptr != nullptr) {
		parent = ptr;
		val = CompareKeys (ptr->m_key, key);

		if (val < 0) {
			ptr = ptr->GetLeft();
		} else if (val > 0) {
			ptr = ptr->GetRight();
		} else {
			return nullptr;
		}
	}

	m_count	++;

	ptr = node;
	ptr->m_key = key;
	ptr->Initdata (parent);

	if (!parent) {
		m_head = ptr;
	} else {
		if (val < 0) {
			parent->m_left = ptr; 
		} else {
			parent->m_right = ptr;
		}
	}
	ptr->InsertFixup ((dTreeNode**)&m_head);
	return ptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Replace (OBJECT &element, KEY key)
{
	dTreeNode* parent = nullptr;
	dTreeNode* ptr = m_head;
	int val = 0;
	while (ptr != nullptr) {
		parent = ptr;
		val = CompareKeys (ptr->m_key, key);
		if (val == 0) {
			ptr->m_info = element;
			return ptr;
		}
		if (val < 0) {
			ptr = ptr->GetLeft();
		} else {
			ptr = ptr->GetRight();
		}
	}

	ptr = new dTreeNode (element, key, parent);
	if (!parent) {
		m_head = ptr;
	} else {
		if (val < 0) {
			parent->m_left = ptr; 
		} else {
			parent->m_right = ptr;
		}
	}
	ptr->InsertFixup ((dTreeNode**)&m_head);
	return ptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::ReplaceKey (typename dMap<OBJECT, KEY>::dTreeNode* node, KEY key)
{
	Unlink(node);
	dTreeNode* const ptr = Insert (node, key);

	dAssert (ptr);
	return ptr;
}

template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::ReplaceKey (KEY oldKey, KEY newKey)
{
	dTreeNode* const node = Find (oldKey);
	return node ? ReplaceKey (node, newKey) : nullptr;
}

template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Unlink (typename dMap<OBJECT, KEY>::dTreeNode* const node)
{
	m_count	--;
	node->Unlink((dTreeNode** )&m_head);
}

template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Remove (typename dMap<OBJECT, KEY>::dTreeNode* const node)
{
	m_count	--;
	node->Unlink ((dTreeNode** )&m_head);
	delete node;
}

template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Remove (KEY key) 
{
	// find node in tree 
	dTreeNode* const node = Find (key);
	if (node) {
		Remove (node);
	}
}


template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::RemoveAllLow (dTreeNode* const root) 
{
	if (root->m_left) {
		RemoveAllLow((dTreeNode*)root->m_left);
	}
	if (root->m_right) {
		RemoveAllLow ((dTreeNode*)root->m_right);
	}
	root->SetInTreeFlag(false);
	delete root;
}


template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::RemoveAll () 
{
	if (m_head) {
		m_count	 = 0;
		dTreeNode* root;
		for (root = m_head; root->m_parent; root = (dTreeNode*)root->m_parent);
		RemoveAllLow(root);
		m_head = nullptr;
	}
}

template<class OBJECT, class KEY>
bool dMap<OBJECT, KEY>::SanityCheck () const
{
	return SanityCheck (m_head, 0);
}


template<class OBJECT, class KEY>
bool dMap<OBJECT, KEY>::SanityCheck (typename dMap<OBJECT, KEY>::dTreeNode* ptr, int height) const
{
	if (!ptr) {
		return true;
	}

	if (ptr->m_left) {
		if (CompareKeys (ptr->m_key, ptr->GetLeft()->m_key) > 0) {
			return false;
		}
	}

	if (ptr->m_right) {
		if (CompareKeys (ptr->m_key, ptr->GetRight()->m_key) < 0) {
			return false;
		}
	}

	if (ptr->GetColor() == dTreeNode::BLACK) {
		height ++;
	} else if (!((!ptr->m_left  || (ptr->m_left->GetColor() == dTreeNode::BLACK)) &&
		       (!ptr->m_right || (ptr->m_right->GetColor() == dTreeNode::BLACK)))) {
	  	return false;
	}

	if (!ptr->m_left && !ptr->m_right) {
		int bh = 0;
		for (dTreeNode* x = ptr; x; x = x->GetParent()) {
	 		if (x->GetColor() == dTreeNode::BLACK) {
				bh ++;
			}
		}
		if (bh != height) {
			return false;
		}
	}

	if (ptr->m_left && !SanityCheck (ptr->GetLeft(), height)) {
		return false;
	}

	if (ptr->m_right && !SanityCheck (ptr->GetRight(), height)) {
		return false;
	}
	return true;
}

template<class OBJECT, class KEY>
int dMap<OBJECT, KEY>::CompareKeys (const KEY &key0, const KEY &key1) const
{
	if (key1 < key0) {
		return - 1;
	}
	if (key1 > key0) {
		return 1;
	}
	return 0;
}

#endif


