#pragma once

template<class T> class Collection
{
protected:
	unsigned long count;
public:
	Collection() : count(0) {}

	virtual void clear() = 0;
	virtual void add(const T &val) = 0;
	virtual const bool remove(const T &val) = 0;

	const unsigned long size() const { return count; }
};

template<class T> class Node
{
public:
	T val;

	Node(const T &v) : val(v) {}
	virtual ~Node() {}
};

template<class T> class ListNode : public Node < T >
{
public:
	ListNode<T> *next, *prev;

	ListNode(const T &v) : Node<T>(v), next(nullptr), prev(nullptr) {}
	virtual ~ListNode()
	{
		if (next) next->prev = prev;
		if (prev) prev->next = next;
	}
};

template<class T> class LinkedList : public Collection < T >
{
protected:
	ListNode<T> *head, *tail;

public:
	class Iterator
	{
		friend class LinkedList < T >;
	protected:
		ListNode<T> *n;
		Iterator(ListNode<T> *start) : n(start) {}
	public:
		Iterator(const Iterator &other) : n(other.n) {}

		virtual T &val() { return n->val; }
		virtual void next() { if (n) n = n->next; }
		virtual void prev() { if (n) n = n->prev; }
		virtual const bool has_val() { return (n ? true : false); }
	};

	LinkedList() : Collection<T>(), head(nullptr), tail(nullptr) {};
	LinkedList(const LinkedList<T> &other) : Collection<T>(), head(nullptr), tail(nullptr)
	{
		for (Iterator i = other.begin(); i.has_val(); i.next())
			add(i.val());
	}
	virtual ~LinkedList() { clear(); }

	LinkedList<T> &operator=(const LinkedList<T> &other)
	{
		clear();
		for (Iterator i = other.begin(); i.has_val(); i.next())
			add(i.val());
		return *this;
	}

	virtual void clear()
	{
		ListNode<T> *n;
		while (head) {
			n = head;
			head = head->next;
			delete n;
		}
		tail = nullptr;
		Collection<T>::count = 0;
	}

	virtual Iterator begin() const { return Iterator(head); }

	virtual void add_front(T &val)
	{
		ListNode<T> *n = new ListNode<T>(val);
		n->next = head;
		if (head) head->prev = n;
		head = n;
		if (!tail) tail = n;
		Collection<T>::count++;
	}

	virtual void add(const T &val)
	{
		ListNode<T> *n = new ListNode<T>(val);
		n->prev = tail;
		if (tail) tail->next = n;
		tail = n;
		if (!head) head = n;
		Collection<T>::count++;
	}

	virtual const bool remove(const T &val)
	{
		ListNode<T> *n = head;
		while (n) {
			if (n->val == val) {
				if (n == head) head = head->next;
				if (n == tail) tail = tail->prev;

				delete n;
				Collection<T>::count--;
				return true;
			}
			else
				n = n->next;
		}

		return false;
	}

	virtual const bool contains(T &val) const
	{
		ListNode<T> *n = head;
		while (n) {
			if (n->val == val) {
				return true;
			}
			else
				n = n->next;
		}

		return false;
	}

	// queue/stack functions
	// stack - use push/pop
	// queue - use push_back/pop
	virtual void push(T val)
	{
		add_front(val);
	}

	virtual void push_back(T &val)
	{
		add(val);
	}

	virtual const bool pop(T &val)
	{
		if (!head) return false;

		ListNode<T> *n = head;
		if (head) {
			head = head->next;
			if (n == tail) tail = nullptr;
			val = n->val;
			delete n;
			Collection<T>::count--;
			return true;
		}
		else
			return false;
	}
};

template<class T> class DynamicArray : public Collection < T >
{
protected:
	T *ar;

	unsigned long initial, limit, increment;

public:
	class Iterator
	{
		friend class DynamicArray < T >;
	protected:
		T *ar;
		unsigned long count;
		unsigned long pos;
		Iterator(T *a, const int c, unsigned long p) : ar(a), count(c), pos(p) {}
	public:
		Iterator(const Iterator &other) : ar(other.ar), count(other.count), pos(other.pos) {}

		virtual T &val() { return ar[pos]; }
		virtual void next() { pos++; }
		virtual void prev() { pos--; }
		virtual const bool has_val() { return pos < count; }
	};

	DynamicArray(unsigned long init = 0, unsigned long inc = 1) : Collection<T>(), ar(0), initial(init), limit(init), increment(inc)
	{
		if (limit) ar = (T *)malloc(limit * sizeof(T));
	}
	virtual ~DynamicArray() { if (ar) free(ar); }

	virtual void clear()
	{
		Collection<T>::count = 0;
		limit = initial;
		if (limit) ar = (T *)realloc(ar, limit * sizeof(T));
		else {
			free(ar);
			ar = 0;
		}
	}

	virtual Iterator begin() const { return Iterator(ar, Collection<T>::count, 0); }

	virtual void add(const T &val)
	{
		if (Collection<T>::count == limit) {
			limit += increment;
			ar = (T *)realloc(ar, limit * sizeof(T));
			ar[Collection<T>::count++] = val;
		}
		else
			ar[Collection<T>::count++] = val;
	}

	virtual void add_all(DynamicArray<T> &other)
	{
		for (Iterator i = other.begin(); i != pl.end(); ++i) {
			add(i.val());
		}
	}

	virtual const bool remove(const T &val)
	{
		for (unsigned long i = 0; i < Collection<T>::count; i++) {
			if (ar[i] == val) {
				memmove(ar + i, ar + i + 1, (Collection<T>::count - i) * sizeof(T));
				Collection<T>::count--;
				return true;
			}
		}
		return false;
	}

	virtual const bool remove(const unsigned long index)
	{
		if (index >= Collection<T>::count) return false;

		memmove(ar + index, ar + index + 1, (Collection<T>::count - index) * sizeof(T));
		Collection<T>::count--;
		return true;
	}

	virtual const bool insert(const T &val, const unsigned long index)
	{
		if (index > Collection<T>::count) return false;

		if (Collection<T>::count == limit) {
			limit += increment;
			ar = (T *)realloc(ar, limit * sizeof(T));
		}

		if (index < Collection<T>::count)
			memmove(ar + index + 1, ar + index, (Collection<T>::count - index) * sizeof(T));

		ar[index] = val;
		Collection<T>::count++;
		return true;
	}

	virtual T &operator[](const int index)
	{
		return ar[index];
	}

	const bool index_of(const T &val, unsigned long &index) const
	{
		for (int i = 0; i < Collection<T>::count; i++) {
			if (ar[index] == val) {
				index = i;
				return true;
			}
		}
		return false;
	}

	const int index_of(const T &val) const
	{
		for (int i = 0; i < Collection<T>::count; i++) {
			if (ar[i] == val) {
				return i;
			}
		}
		return -1;
	}

	// stack functions
	virtual const bool pop(T &val)
	{
		if (Collection<T>::count) {
			val = ar[Collection<T>::count - 1];
			remove(Collection<T>::count - 1);
			return true;
		}
		return false;
	}

	virtual void push(const T &val)
	{
		add(val);
	}
};

template<class T> class SortedDynamicArray : public DynamicArray < T >
{
public:
	SortedDynamicArray(unsigned long init = 0, unsigned long inc = 1) : DynamicArray<T>(init, inc) {}
	virtual ~SortedDynamicArray() {}

	const bool get_index(const T &val, unsigned long &index)
	{
		unsigned long low = 0;
		unsigned long high = Collection<T>::count - 1;

		while (high < Collection<T>::count && low <= high) {
			unsigned long i = (low + high) / 2;
			if (DynamicArray<T>::ar[i] == val) {
				index = i;
				return true;
			}
			else
				if (DynamicArray<T>::ar[i] < val)
					low = i + 1;
				else
					high = i - 1;
		}

		index = low;
		return false;
	}

	virtual void add(const T &val)
	{
		unsigned long index;
		get_index(val, index);
		insert(val, index);
	}
};

template<class T> class TreeNode : public Node < T >
{
public:
	TreeNode<T> *parent, *left, *right;

	TreeNode(const T &v, TreeNode<T> *par) : Node<T>(v), parent(par), left(0), right(0) {}
	virtual ~TreeNode()
	{
		if (parent) {
			if (parent->left == this) parent->left = 0;
			if (parent->right == this)parent->right = 0;
		}
	}
};

template<class T, class N = TreeNode<T> > class BinaryTree : public Collection < T >
{
protected:

	N *root;

	virtual void delete_node(N *n)
	{
		if (n->left && n->right) {
			N *minmax = n->left;
			while (minmax->right) minmax = minmax->right;
			n->val = minmax->val;
			delete_node(minmax);
			return;
		}
		else if (n->right) {
			if (n->parent) {
				if (n->parent->left == n) n->parent->left = n->right;
				else n->parent->right = n->right;
			}
			else
				root = n->right;
			n->right->parent = n->parent;
		}
		else if (n->left) {
			if (n->parent) {
				if (n->parent->left == n)	n->parent->left = n->left;
				else n->parent->right = n->left;
			}
			else
				root = n->left;
			n->left->parent = n->parent;
		}
		else {
			if (n == root) root = nullptr;
		}
		delete n;
		Collection<T>::count--;
	}

	virtual void insert_node(N *n)
	{
		N *current = root, *parent = nullptr;
		while (current) {
			parent = current;
			if (n->val < current->val)
				current = current->left;
			else
				current = current->right;
		}

		if (parent) {
			if (n->val < parent->val) {
				parent->left = n;
			}
			else {
				parent->right = n;
			}
		}
		else
			root = n;

		n->parent = parent;
		Collection<T>::count++;
	}

public:
	class Iterator
	{
		friend class BinaryTree < T, N >;
	protected:

		class EvalNode
		{
		public:
			bool evaluate;
			N *node;

			EvalNode() : evaluate(false), node(0) {}
			EvalNode(const bool eval, N *n) : evaluate(eval), node(n) {}
			const bool operator==(const EvalNode &other) const { return node == other.node; }
			EvalNode &operator=(const EvalNode &other) { evaluate = other.evaluate; node = other.node; return *this; }

		};

		N *n;
		LinkedList<EvalNode> stack;


		Iterator(N *start) : n(0)
		{
			if (start) {
				stack.push(EvalNode(true, start));
				next();
			}
		}

	public:
		Iterator(const Iterator &other) :n(other.n), stack(other.stack) {}
		virtual ~Iterator() {}

		virtual T &val() { return n->val; }
		virtual void next()
		{
			EvalNode en;
			bool popped = false;
			while ((popped = stack.pop(en)) && en.evaluate) {
				if (en.node->right) stack.push(EvalNode(true, en.node->right));
				stack.push(EvalNode(false, en.node));
				if (en.node->left) stack.push(EvalNode(true, en.node->left));
			}

			n = (popped ? en.node : 0);
		}
		virtual const bool has_val() { return (n ? true : false); }
	};

	BinaryTree() : Collection<T>(), root(nullptr) {};
	BinaryTree(BinaryTree<T> &other) : Collection<T>(), root(nullptr)
	{
		for (Iterator i = other.begin(); i != pl.end(); ++i)
			add(i.val());
	}
	virtual ~BinaryTree() { clear(); }

	BinaryTree &operator=(BinaryTree<T> &other)
	{
		clear();
		for (Iterator i = other.begin(); i != pl.end(); ++i)
			add(i.val());
		return *this;
	}

	virtual void clear()
	{
		N *current = root, *parent = nullptr;
		while (current) {
			if (current->left) current = current->left;
			else if (current->right) current = current->right;
			else {
				parent = current->parent;
				delete current;
				current = parent;
			}
		}

		root = nullptr;
		Collection<T>::count = 0;
	}

	void add(const T &val)
	{
		N *n = new N(val, 0);
		insert_node(n);
	}

	const bool remove(const T &val)
	{
		N *current = root;
		while (current) {
			if (current->val == val)
				break;
			else if (val < current->val)
				current = current->left;
			else
				current = current->right;
		}

		if (current) {
			delete_node(current);
			return true;
		}

		return false;
	}

	const bool contains(const T &val) const
	{
		N *current = root;
		while (current) {
			if (current->val == val)
				break;
			else if (val < current->val)
				current = current->left;
			else
				current = current->right;
		}

		return current != 0;
	}

	Iterator begin() const { return Iterator(root); }
};

#define RED		1
#define BLACK	0

// thanks to wikipedia (http://en.wikipedia.org/wiki/Red_black_tree)
template<class T> class ColouredTreeNode : public Node < T >
{
public:
	ColouredTreeNode<T> *parent, *left, *right;
	char color;

	ColouredTreeNode(const T &v, ColouredTreeNode<T> *par) : Node<T>(v), parent(par), left(nullptr), right(nullptr), color(BLACK) {}
	virtual ~ColouredTreeNode()
	{
		if (parent) {
			if (parent->left == this) parent->left = nullptr;
			if (parent->right == this)parent->right = nullptr;
		}
	}
};

template<class T, class N = ColouredTreeNode<T> > class RedBlackTree : public BinaryTree < T, N >
{
protected:
	N *grandparent(N *n)
	{
		if (n && n->parent)
			return n->parent->parent;
		else
			return NULL;
	}
	N *uncle(N *n)
	{
		if (grandparent(n)) {
			if (n->parent == grandparent(n)->left)
				return grandparent(n)->right;
			else
				return grandparent(n)->left;
		}
		else
			return NULL;
	}
	N *sibling(N *n)
	{
		if (n->parent) {
			if (n == n->parent->left)
				return n->parent->right;
			else
				return n->parent->left;
		}
		else
			return NULL;
	}
	bool is_leaf(N *n)
	{
		return n == 0;
	}

	void replace_node(N *o, N *n)
	{
		n->parent = o->parent;
		if (n->parent) {
			if (n->parent->left == o) n->parent->left = n;
			else if (n->parent->right == o) n->parent->right = n;
		}
		else
			BinaryTree<T, N>::root = n;
	}

	void rotate_left(N *n)
	{
		N *p = n->right;
		N *q = n;

		q->right = p->left;
		if (q->right) q->right->parent = q;
		p->left = q;
		p->parent = q->parent;
		q->parent = p;
		if (p->parent) {
			if (p->parent->left == q) p->parent->left = p;
			else if (p->parent->right == q) p->parent->right = p;
		}
		else
			BinaryTree<T, N>::root = p;
	}
	void rotate_right(N *n)
	{
		N *p = n->left;
		N *q = n;

		q->left = p->right;
		if (q->left) q->left->parent = q;
		p->right = q;
		p->parent = q->parent;
		q->parent = p;
		if (p->parent) {
			if (p->parent->left == q) p->parent->left = p;
			else if (p->parent->right == q) p->parent->right = p;
		}
		else
			BinaryTree<T, N>::root = p;
	}

	void insert_case1(N *n)
	{
		if (n->parent == NULL)
			n->color = BLACK;
		else
			insert_case2(n);
	}
	void insert_case2(N *n)
	{
		if (n->parent->color == BLACK)
			return; /* Tree is still valid */
		else
			insert_case3(n);
	}
	void insert_case3(N *n)
	{
		if (uncle(n) != NULL && uncle(n)->color == RED) {
			n->parent->color = BLACK;
			uncle(n)->color = BLACK;
			grandparent(n)->color = RED;
			insert_case1(grandparent(n));
		}
		else
			insert_case4(n);
	}
	void insert_case4(N *n)
	{
		if (n == n->parent->right && n->parent == grandparent(n)->left) {
			rotate_left(n->parent);
			n = n->left;
		}
		else if (n == n->parent->left && n->parent == grandparent(n)->right) {
			rotate_right(n->parent);
			n = n->right;
		}
		insert_case5(n);
	}
	void insert_case5(N *n)
	{
		n->parent->color = BLACK;
		grandparent(n)->color = RED;
		if (n == n->parent->left && n->parent == grandparent(n)->left) {
			rotate_right(grandparent(n));
		}
		else {
			/* Here, n == n->parent->right && n->parent == grandparent(n)->right */
			rotate_left(grandparent(n));
		}
	}

	void delete_case0(N *n)
	{
		/* Precondition: n has at most one non-null child */
		N *child = is_leaf(n->right) ? n->left : n->right;
		if (child) replace_node(n, child);
		if (n->color == BLACK) {
			if (child) {
				if (child->color == RED)
					child->color = BLACK;
				else
					delete_case1(child);
			}
			else
				delete_case1(n);
		}
		if (BinaryTree<T, N>::root == n) BinaryTree<T, N>::root = 0;
		delete n;
		Collection<T>::count--;
	}
	void delete_case1(N *n)
	{
		if (n->parent == NULL)
			return;
		else
			delete_case2(n);
	}
	void delete_case2(N *n)
	{
		if (sibling(n) && sibling(n)->color == RED) {
			n->parent->color = RED;
			sibling(n)->color = BLACK;
			if (n == n->parent->left)
				rotate_left(n->parent);
			else
				rotate_right(n->parent);
		}
		delete_case3(n);
	}
	void delete_case3(N *n)
	{
		if (n->parent->color == BLACK &&
			sibling(n) &&
			sibling(n)->color == BLACK &&
			(sibling(n)->left == 0 || sibling(n)->left->color == BLACK) &&
			(sibling(n)->right == 0 || sibling(n)->right->color == BLACK)) {
			sibling(n)->color = RED;
			delete_case1(n->parent);
		}
		else
			delete_case4(n);
	}
	void delete_case4(N *n)
	{
		if (n->parent->color == RED &&
			sibling(n) &&
			sibling(n)->color == BLACK &&
			(sibling(n)->left == 0 || sibling(n)->left->color == BLACK) &&
			(sibling(n)->right == 0 || sibling(n)->right->color == BLACK)) {
			sibling(n)->color = RED;
			n->parent->color = BLACK;
		}
		else
			delete_case5(n);
	}
	void delete_case5(N *n)
	{
		if (n == n->parent->left &&
			sibling(n) &&
			sibling(n)->color == BLACK &&
			sibling(n)->left &&
			sibling(n)->left->color == RED &&
			(sibling(n)->right == 0 || sibling(n)->right->color == BLACK)) {
			sibling(n)->color = RED;
			sibling(n)->left->color = BLACK;
			rotate_right(sibling(n));
		}
		else if (n == n->parent->right &&
			sibling(n) &&
			sibling(n)->color == BLACK &&
			sibling(n)->right &&
			sibling(n)->right->color == RED &&
			(sibling(n)->left == 0 || sibling(n)->left->color == BLACK)) {
			sibling(n)->color = RED;
			sibling(n)->right->color = BLACK;
			rotate_left(sibling(n));
		}
		delete_case6(n);
	}
	void delete_case6(N *n)
	{
		sibling(n)->color = n->parent->color;
		n->parent->color = BLACK;
		if (n == n->parent->left) {
			/* Here, sibling(n)->right->color == RED */
			sibling(n)->right->color = BLACK;
			rotate_left(n->parent);
		}
		else {
			/* Here, sibling(n)->left->color == RED */
			sibling(n)->left->color = BLACK;
			rotate_right(n->parent);
		}
	}

	N *get_predecessor(N *n)
	{
		N *minmax = n->left;
		while (minmax->right) minmax = minmax->right;
		return minmax;
	}

	virtual void insert_node(N *n)
	{
		BinaryTree<T, N>::insert_node(n);
		n->color = RED;

		insert_case1(n);
	}

	virtual void delete_node(N *n)
	{
		if (n->left && n->right) {
			N *predecessor = get_predecessor(n);
			n->val = predecessor->val;
			delete_case0(predecessor);
		}
		else
			delete_case0(n);
	}

public:
	RedBlackTree() : BinaryTree< T, N >() {}
	virtual ~RedBlackTree() {}
};

template<class A, class B> class Pair
{
public:
	A first;
	B second;

	Pair(const A &f) : first(f) {}
	Pair(const A &f, const B &s) : first(f), second(s) {}
	Pair(const Pair<A, B> &other) : first(other.first), second(other.second) {}
	virtual ~Pair() {}

	const bool operator<(const Pair<A, B> &other) const { return first < other.first; }
	const bool operator==(const Pair<A, B> &other) const { return first == other.first; }
	Pair<A, B> &operator=(const Pair<A, B> &other) { first = other.first; second = other.second; return *this; }
};

//template<class A, class B, class N = TreeNode<Pair<A, B> > > class Map: public BinaryTree< Pair< A, B >, N > {
template<class A, class B, class N = ColouredTreeNode<Pair<A, B> > > class Map : public RedBlackTree < Pair< A, B >, N >
{
protected:

	N *find(A &key) const
	{
		N *n = RedBlackTree< Pair< A, B >, N >::root;
		while (n) {
			if (n->val.first == key)
				return n;
			else if (key < n->val.first)
				n = n->left;
			else
				n = n->right;

		}
		return 0;
	}
public:
	//Map(): BinaryTree< Pair<A,B>, N >() {}
	Map() : RedBlackTree< Pair<A, B>, N >() {}
	virtual ~Map() {}

	void put(A &key, B &value)
	{
		add(Pair<A, B>(key, value));
	}

	const bool get(A &key, B &val) const
	{
		const N *n = find(key);
		if (n) {
			val = n->val.second;
			return true;
		}
		else
			return false;
	}

	B &operator[](A &key)
	{
		N *n = find(key);
		if (n)
			return n->val.second;
		else {
			Pair< A, B > p(key);
			n = new N(p, 0);
			insert_node(n);
			return n->val.second;
		}
	}

	virtual const bool exists(A &key) const
	{
		return find(key) != NULL;
	}

	virtual const bool remove(A &key)
	{
		N *n = find(key);
		if (n) {
			delete_node(n);
			return true;
		}
		else
			return false;
	}
};