#include <iostream>

#ifndef BINARYTREE_CLASS_INCLUDED
#define BINARYTREE_CLASS_INCLUDED

/*
	Binary Tree Class (BinaryTree)
	LastModification : 2008. 5. 15
	Version : 1.1.0
	myllyj(myllyj at myllyj dot com) / http://program.myllyj.com

	Comment :
		±âÁ¸ BTree Class´Â ¸Þ¼Òµåµµ ³­ÀâÇÏ°í, namingÀÌ ÇÞ°¥¸®°Ô µÇ¾î ÀÖ¾î¼­
		»õ·Ó°Ô Å¬·¡½º¸¦ ÀÛ¼ºÇÔ.
		»õ BinaryTreeÅ¬·¡½º´Â ÀÌÀü BTreeÅ¬·¡½º¿Í ÀüÇô È£È¯ÀÌ µÇÁö ¾ÊÀ¸¸ç,
		¸Þ¼Òµå¸í¸í¹ýÀº C#ÇüÅÂ¸¦ µû¸£°í ÀÖÀ½.

	History
		1.1.0 - Æ®¸® ±íÀÌ ÃøÁ¤ ±â´É Ãß°¡
		1.1.0 - Æ®¸® »èÁ¦°¡ ¾Æ´Ñ Unlink ±â´É Ãß°¡

*/

template <class T>
class BinaryTree
{
	
private :
	T data;
	BinaryTree<T>* parent;
	BinaryTree<T>* left;
	BinaryTree<T>* right;
	int nowDepth;
	int resultDepth;

	void innerDFS(BinaryTree<T>* node);
	
public:
	BinaryTree();
	BinaryTree(const T& data);
	BinaryTree(const T& data, BinaryTree<T>* parent);


	void SetLeftChild(const T & data);
	void SetLeftChild(BinaryTree<T>* node);
	void SetRightChild(const T & data);
	void SetRightChild(BinaryTree<T>* node);
	void SetParent(BinaryTree<T>* node);

	void RemoveLeftChild();
	void RemoveRightChild();

	BinaryTree<T>* UnlinkLeftChild();
	BinaryTree<T>* UnlinkRightChild();

	int CountChild();

	void SetData(const T & data);
	T GetData();

	BinaryTree<T>* GetLeftChild();
	BinaryTree<T>* GetRightChild();
	BinaryTree<T>* GetParent();

	int GetDepth();

};

template <class T>
BinaryTree<T>::BinaryTree()
{
	this->parent = NULL;
	this->left = NULL;
	this->right = NULL;
}

template <class T>
BinaryTree<T>::BinaryTree(const T &data)
{
	this->parent = NULL;
	this->data = data;
	this->left = NULL;
	this->right = NULL;
}

template <class T>
BinaryTree<T>::BinaryTree(const T &data, BinaryTree<T> *parent)
{
	this->parent = parent;
	this->data = data;
	this->left = NULL;
	this->right = NULL;
}

// BinaryTree°¡ °¡Áö°í ÀÖ´Â ChildÀÇ °¹¼ö¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù.
template <class T>
int BinaryTree<T>::CountChild()
{
	int count = 0;

	if (this->left!=NULL) count++;
	if (this->right!=NULL) count++;

	return count;
}

// BinaryTreeÀÇ µ¥ÀÌÅÍ °ªÀ» ¹ÝÈ¯ÇÕ´Ï´Ù.
template <class T>
T BinaryTree<T>::GetData()
{
	return this->data;
}

// BinaryTreeÀÇ µ¥ÀÌÅÍ °ªÀ» ¼³Á¤ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::SetData(const T& data)
{
	this->data = data;
}

// ¿ÞÂÊ ¼­ºêÆ®¸®¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù.
template <class T>
BinaryTree<T>* BinaryTree<T>::GetLeftChild()
{
	return this->left;
}

// ¿À¸¥ÂÊ ¼­ºêÆ®¸®¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù.
template <class T>
BinaryTree<T>* BinaryTree<T>::GetRightChild()
{
	return this->right;
}

// ¿ÞÂÊ ¼­ºêÆ®¸®¸¦ ÁöÁ¤ÇÕ´Ï´Ù. ÁöÁ¤ÇÏ´Â ¼­ºêÆ®¸®ÀÇ ºÎ¸ð´Â ÇöÀç Æ®¸®·Î ¼³Á¤µË´Ï´Ù.
template <class T>
void BinaryTree<T>::SetLeftChild(BinaryTree<T> *node)
{
	this->left = node;
	if (this->left!=NULL) this->left->SetParent(this);
}

// ¿ÞÂÊ Child¿¡ µ¥ÀÌÅÍ¸¦ ¼³Á¤ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::SetLeftChild(const T &data)
{
	this->left = new BinaryTree<T>(data, this);
}

// ¿À¸¥ÂÊ ¼­ºêÆ®¸®¸¦ ÁöÁ¤ÇÕ´Ï´Ù. ÁöÁ¤ÇÏ´Â ¼­ºêÆ®¸®ÀÇ ºÎ¸ð´Â ÇöÀç Æ®¸®·Î ¼³Á¤µË´Ï´Ù.
template <class T>
void BinaryTree<T>::SetRightChild(BinaryTree<T> *node)
{
	this->right = node;
	if (this->right!=NULL) this->right->SetParent(this);
}

// ¿À¸¥ÂÊ Child¿¡ µ¥ÀÌÅÍ¸¦ ¼³Á¤ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::SetRightChild(const T &data)
{
	this->right = new BinaryTree<T>(data, this);
}

// ¿ÞÂÊ ¼­ºêÆ®¸®¸¦ »èÁ¦ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::RemoveLeftChild()
{
	if (this->left==NULL) return;
	if (this->left->CountChild()==0) delete this->left;
	this->left = NULL;
}

// ¿À¸¥ÂÊ ¼­ºêÆ®¸®¸¦ »èÁ¦ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::RemoveRightChild()
{
	if (this->right==NULL) return;
	if (this->right->CountChild()==0) delete this->right;
	this->right = NULL;
}

// ºÎ¸ð Æ®¸®¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù.
template <class T>
BinaryTree<T>* BinaryTree<T>::GetParent()
{
	return this->parent;
}

// ºÎ¸ð Æ®¸®¸¦ ÁöÁ¤ÇÕ´Ï´Ù.
template <class T>
void BinaryTree<T>::SetParent(BinaryTree<T> *node)
{
	this->parent = node;
}

// ¿ÞÂÊ ¼­ºêÆ®¸®¿Í ¿¬°áÀ» ²÷½À´Ï´Ù.
template <class T>
BinaryTree<T>* BinaryTree<T>::UnlinkLeftChild()
{
	BinaryTree<T>* result = this->left;
	this->left = NULL;
	return this->left;
}

// ¿À¸¥ÂÊ ¼­ºêÆ®¸®¿Í ¿¬°áÀ» ²÷½À´Ï´Ù.
template <class T>
BinaryTree<T>* BinaryTree<T>::UnlinkRightChild()
{
	BinaryTree<T>* result = this->right;
	this->right = NULL;
	return this->right;
}

template <class T>
void BinaryTree<T>::innerDFS(BinaryTree<T>* node)
{
	if (node==NULL) return;

	this->nowDepth ++;
	if (nowDepth > this->resultDepth) resultDepth = nowDepth;

	if (node->GetLeftChild()!=NULL)
	{
		this->innerDFS(node->GetLeftChild());
		nowDepth--;
	}

	if (node->GetRightChild()!=NULL)
	{
		this->innerDFS(node->GetRightChild());
		nowDepth--;
	}

	return;
}

// ÀÌ Æ®¸®ÀÇ Depth¸¦ ±¸ÇÕ´Ï´Ù.
template <class T>
int BinaryTree<T>::GetDepth()
{
	nowDepth = 0;
	resultDepth = 0;
	this->innerDFS(this);
	return this->resultDepth;
}

#endif
