#ifndef FRAMEWORK_CONTAINER_BINARYTREE_H_
#define FRAMEWORK_CONTAINER_BINARYTREE_H_

#include <stddef.h>
#include <stdint.h>
#include <map>
template<typename Tp>
class BinaryNode {
public:
	BinaryNode(Tp* setValue) :
			value(setValue), left(NULL), right(NULL), parent(NULL) {
	}
	Tp *value;
	BinaryNode* left;
	BinaryNode* right;
	BinaryNode* parent;
};

template<typename Tp>
class ExplicitNodeIterator {
public:
	typedef ExplicitNodeIterator<Tp> _Self;
	typedef BinaryNode<Tp> _Node;
	typedef Tp value_type;
	typedef Tp* pointer;
	typedef Tp& reference;
	ExplicitNodeIterator() :
			element(NULL) {
	}
	ExplicitNodeIterator(_Node* node) :
			element(node) {
	}
	BinaryNode<Tp>* element;
	_Self up() {
		return _Self(element->parent);
	}
	_Self left() {
		if (element != NULL) {
			return _Self(element->left);
		} else {
			return _Self(NULL);
		}

	}
	_Self right() {
		if (element != NULL) {
			return _Self(element->right);
		} else {
			return _Self(NULL);
		}

	}
	bool operator==(const _Self& __x) const {
		return element == __x.element;
	}
	bool operator!=(const _Self& __x) const {
		return element != __x.element;
	}
    pointer
    operator->() const {
    	if (element != NULL) {
    		return element->value;
    	} else {
    		return NULL;
    	}
    }
    pointer operator*() const {
    	return this->operator->();
    }
};

/**
 * Pretty rudimentary version of a simple binary tree (not a binary search tree!).
 */
template<typename Tp>
class BinaryTree {
public:
	typedef ExplicitNodeIterator<Tp> iterator;
	typedef BinaryNode<Tp> Node;
	typedef std::pair<iterator, iterator> children;
	BinaryTree() :
			rootNode(NULL) {
	}
	BinaryTree(Node* rootNode) :
			rootNode(rootNode) {
	}
	iterator begin() const {
		return iterator(rootNode);
	}
	static iterator end() {
		return iterator(NULL);
	}
	iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) {
		newNode->parent = parentNode.element;
		if (parentNode.element != NULL) {
			if (insertLeft) {
				parentNode.element->left = newNode;
			} else {
				parentNode.element->right = newNode;
			}
		} else {
			//Insert first element.
			rootNode = newNode;
		}
		return iterator(newNode);
	}
	//No recursion to children. Needs to be done externally.
	children erase(iterator node) {
		if (node.element == rootNode) {
			//We're root node
			rootNode = NULL;
		} else {
			//Delete parent's reference
			if (node.up().left() == node) {
				node.up().element->left = NULL;
			} else {
				node.up().element->right = NULL;
			}
		}
		return children(node.element->left, node.element->right);
	}
	static uint32_t countLeft(iterator start) {
		if (start == end()) {
			return 0;
		}
		//We also count the start node itself.
		uint32_t count = 1;
		while (start.left() != end()) {
			count++;
			start = start.left();
		}
		return count;
	}
	static uint32_t countRight(iterator start) {
		if (start == end()) {
			return 0;
		}
		//We also count the start node itself.
		uint32_t count = 1;
		while (start.right() != end()) {
			count++;
			start = start.right();
		}
		return count;
	}

protected:
	Node* rootNode;
};



#endif /* FRAMEWORK_CONTAINER_BINARYTREE_H_ */