#pragma once

#include "bvolumes.h"

#ifndef SAFE_DELETE
#define SAFE_DELETE(ptr)			{	if (ptr)	{	delete ptr;		ptr = nullptr;		}		}
#endif

namespace bTree
{
	template <typename TreeNodeType> class BinTreeNode
	{
	private:
		BinTreeNode();									// default constructor is not allowed, because parent, lChild and rChild must be specified
		BinTreeNode(const BinTreeNode &);				// copy constructor is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild
		BinTreeNode &operator= (const BinTreeNode &);	// assign operator is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild

	protected:
		// UNRESOLVED What about (TreeNodeType *_parent = nullptr, TreeNodeType *_lChild = nullptr, TreeNodeType *_rChild = nullptr)?
		BinTreeNode(TreeNodeType *_parent, TreeNodeType *_lChild, TreeNodeType *_rChild): parent(_parent), lChild(_lChild), rChild(_rChild) {}
		
	public:

		// Note that destruction of parent, lChild and rChild is not a part of BinTreeNode, it must be a part of inheriting class
		TreeNodeType	*parent;
		TreeNodeType	*lChild;
		TreeNodeType	*rChild;

		// Note that all the following functions are inlined by compiler
		TreeNodeType *GetLChild()				{	return lChild;		}
		TreeNodeType *GetRChild()				{	return rChild;		}
		TreeNodeType *GetParent()				{	return parent;		}
		const TreeNodeType *GetLChild() const	{	return lChild;		}
		const TreeNodeType *GetRChild() const	{	return rChild;		}
		const TreeNodeType *GetParent() const	{	return parent;		}

		void SafeDeleteLChild()			{	SAFE_DELETE(lChild);		}
		void SafeDeleteRChild()			{	SAFE_DELETE(rChild);		}
		void SafeDeleteChilds()			{	SafeDeleteLChild();		SafeDeleteRChild();		}

		bool IsRoot() const				{	return nullptr != parent;		}
		bool IsLeaf() const				{	return (nullptr == lChild)/* && (nullptr == rChild)*/;		}
		bool IsInternal() const			{	return (nullptr != lChild)/* && (nullptr != rChild)*/;		}		// Internal means it has BOTH children
	};

	template <typename TreeNodeType> class BinTree
	{
	private:
		BinTree();									// default constructor is not allowed, because root must be specified
		BinTree(const BinTree &);					// copy constructor is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild
		BinTree &operator= (const BinTree &);		// assign operator is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild

	protected:
		// UNRESOLVED What about (TreeNodeType *_parent = nullptr)?
		BinTree(TreeNodeType *_root): root(_root) {}
		
	public:
		TreeNodeType	*root;

		TreeNodeType *GetRoot()					{	return root;	}
		const TreeNodeType *GetRoot() const		{	return root;	}

		void SafeDeleteRoot()		{	SAFE_DELETE(root);		}
	};

	template <typename TreeNodeType> class BinTreeNodeWithAABB : public BinTreeNode<TreeNodeType>
	{
	// Define "public static void TreeNodeType::UpdateBVNodeStatic(TreeNodeType *node)" in TreeNodeType class.
	// This function is responsible to update aabb of the node (based on its data or aabb of children.
	// The function needs not to update aabb of children or parents
	private:
		BinTreeNodeWithAABB();											// default constructor is not allowed, because parent, lChild and rChild must be specified
		BinTreeNodeWithAABB(const BinTreeNodeWithAABB &);				// copy constructor is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild
		BinTreeNodeWithAABB &operator= (const BinTreeNodeWithAABB &);	// assign operator is not allowed, because I don't know whether to create deep copies or shallow copies of parent, lChild and rChild

	protected:
		// UNRESOLVED What about (TreeNodeType *_parent = nullptr, TreeNodeType *_lChild = nullptr, TreeNodeType *_rChild = nullptr)?
		BinTreeNodeWithAABB(TreeNodeType *_parent, TreeNodeType *_lChild, TreeNodeType *_rChild): BinTreeNode<TreeNodeType>(_parent, _lChild, _rChild), isAABBDirty(true) {}
		bool isAABBDirty;
		void SetAABBDirty() {isAABBDirty=true;}
		void SetAABBUndirty() {isAABBDirty=false;}

	public:
		VRUT::AABB		aabb;

		const VRUT::AABB &GetAABB() const		{	return aabb;	}

		bool IsAABBDirty() const {return isAABBDirty;}

		// Updates BV of children and this node
		void UpdateBVSubtree()
		{
			if (!IsAABBDirty())
				return;
			// Update subtree
			if (this->lChild)			this->lChild->UpdateBVSubtree();
			if (this->rChild)			this->rChild->UpdateBVSubtree();
			TreeNodeType::UpdateBVNodeStatic((TreeNodeType *)this);		// This is safe typecast since the caller is of the type TreeNodeType
		}

		void UpdateBVUptreeOfDirty()
		{
			BinTreeNodeWithAABB<TreeNodeType> *node=this;
			while (node->IsAABBDirty() && !(node->GetLChild() && node->GetLChild()->IsAABBDirty()) && !(node->GetRChild() && node->GetRChild()->IsAABBDirty()))
			{
				TreeNodeType::UpdateBVNodeStatic((TreeNodeType *)node);		// This is safe typecast since the caller is of the type TreeNodeType
				node = node->GetParent();
				if (!node)
					break;
			}
		}

		// Updates BV of this node and its parents
		void UpdateBVUptree()
		{
			BinTreeNodeWithAABB<TreeNodeType> *node=this;
			do 
			{
				TreeNodeType::UpdateBVNodeStatic((TreeNodeType *)node);		// This is safe typecast since the caller is of the type TreeNodeType
				node = node->parent;
			} while (node);
		}

		void DirtyAABBAndWorldMatrixThisAndUptree()
		{
			BinTreeNodeWithAABB<TreeNodeType> *node=this;
			while (node && !node->IsAABBDirty())
			{
				node->SetAABBDirty();
				node=node->GetParent();
			}
		}
	};
}
