#ifndef MAP_ITERATOR_HPP
# define MAP_ITERATOR_HPP

# include <cstddef>		// NULL, ptrdiff_t
# include <iterator>	// iterator_tag

# include "pair.hpp"
# include "map_node.hpp"

namespace ft {

template <
	typename Key,
	typename T,
	typename Compare,
	typename Allocator
> class map_iterator {

private:
	typedef map_iterator	self;

public:
	typedef std::bidirectional_iterator_tag		iterator_category;
	typedef pair<const Key, T>					value_type;
	typedef std::ptrdiff_t						difference_type;
	typedef value_type*							pointer;
	typedef value_type&							reference;

	map_iterator() : _node(), _sentinel() {}
	map_iterator(node<value_type>* n, sentinel<value_type>* sentinel)
		: _node(n), _sentinel(sentinel) {}

	reference	operator*() const {
		return _node->value; }
	pointer		operator->() const {
		return &_node->value; }

	self&	operator++() {
		if (_node == NULL)
			_node = _sentinel->child->min();
		else if (_node->right)
			_node = _node->right->min();
		else
		{
			node<value_type>*	up = _node->up;
			while (up != NULL && _node == up->right)
			{
				_node = up;
				up = up->up;
			}
			_node = up;
		}
		return *this;
	}

	self&	operator--() {
		if (_node == NULL)
			_node = _sentinel->child->max();
		else if (_node->left)
			_node = _node->left->max();
		else
		{
			node<value_type>*	up = _node->up;
			while (up != NULL && _node == up->left)
			{
				_node = up;
				up = up->up;
			}
			_node = up;
		}
		return *this;
	}
	
	self	operator++(int) {
		self old = *this;
		++(*this);
		return old;
	}

	self	operator--(int) {
		self old = *this;
		--(*this);
		return old;
	}	

	node<value_type>* getNode() { return _node; }
	const node<value_type>* getNode() const { return _node; }
	const sentinel<value_type>* getSentinel() const { return _sentinel; }

	friend bool operator==(const self &lhs, const self &rhs) {
		return lhs._node == rhs._node; }
	friend bool operator!=(const self &lhs, const self &rhs) {
		return !(lhs._node == rhs._node); }

private:
	node<value_type>*		_node;
	sentinel<value_type>*	_sentinel;
};

template <
	typename Key,
	typename T,
	typename Compare,
	typename Allocator
> class map_const_iterator {

private:
	typedef map_const_iterator	self;

public:
	typedef std::bidirectional_iterator_tag		iterator_category;
	typedef pair<const Key, T>					value_type;
	typedef std::ptrdiff_t						difference_type;
	typedef const value_type*					pointer;
	typedef const value_type&					reference;

	map_const_iterator() : _node(), _sentinel() {}
	map_const_iterator (
		const node<value_type>* node,
		const sentinel<value_type>* sentinel)
		: _node(node), _sentinel(sentinel) {}
	map_const_iterator (const map_iterator< Key, T, Compare, Allocator >& src)
		: _node(src.getNode()), _sentinel(src.getSentinel()) {}

	reference	operator*() const {
		return _node->value; }
	pointer		operator->() const {
		return &_node->value; }

	self&	operator++() {
		if (_node == NULL)
			_node = _sentinel->child->min();
		else if (_node->right)
			_node = _node->right->min();
		else
		{
			node<value_type>*	up = _node->up;
			while (up != NULL && _node == up->right)
			{
				_node = up;
				up = up->up;
			}
			_node = up;
		}
		return *this;
	}

	self&	operator--() {
		if (_node == NULL)
			_node = _sentinel->child->max();
		else if (_node->left)
			_node = _node->left->max();
		else
		{
			node<value_type>*	up = _node->up;
			while (up != NULL && _node == up->left)
			{
				_node = up;
				up = up->up;
			}
			_node = up;
		}
		return *this;
	}
	
	self	operator++(int) {
		self old = *this;
		++(*this);
		return old;
	}

	self	operator--(int) {
		self old = *this;
		--(*this);
		return old;
	}	

	node<value_type>*	getNode() const {
		return _node; }

	friend bool operator==(const self &lhs, const self &rhs) {
		return lhs._node == rhs._node; }
	friend bool operator!=(const self &lhs, const self &rhs) {
		return !(lhs._node == rhs._node); }

private:
	const node<value_type>*			_node;
	const sentinel<value_type>*		_sentinel;
};

} // namespace ft

#endif

