
#if !defined(INCLUDED_SIGNAL_H)
#define INCLUDED_SIGNAL_H

#include "isignal.h"
#include "memory/allocator.h"
#include "debugging/debugging.h"
#include <iterator>

namespace ListDetail {
struct ListNodeBase {
	ListNodeBase* next;
	ListNodeBase* prev;
};

inline void list_initialise(ListNodeBase& self) {
	self.next = self.prev = &self;
}

inline void list_swap(ListNodeBase& self, ListNodeBase& other) {
	ListNodeBase tmp(self);
	if (other.next == &other) {
		list_initialise(self);
	} else {
		self = other;
		self.next->prev = self.prev->next = &self;
	}
	if (tmp.next == &self) {
		list_initialise(other);
	} else {
		other = tmp;
		other.next->prev = other.prev->next = &other;
	}
}

inline void node_link(ListNodeBase* node, ListNodeBase* next) {
	node->next = next;
	node->prev = next->prev;
	next->prev = node;
	node->prev->next = node;
}
inline void node_unlink(ListNodeBase* node) {
	node->prev->next = node->next;
	node->next->prev = node->prev;
}

template<typename Value>
struct ListNode : public ListNodeBase {
	Value value;

	ListNode(const Value& value) : value(value) {
	}
	ListNode* getNext() const {
		return static_cast<ListNode*>(next);
	}
	ListNode* getPrev() const {
		return static_cast<ListNode*>(prev);
	}
};

template<typename Type>
class NonConstTraits {
public:
	typedef Type value_type;
	typedef value_type* pointer;
	typedef value_type& reference;

	template<typename Other>
	struct rebind {
		typedef NonConstTraits<Other> other;
	};
};

template<typename Type>
class ConstTraits {
public:
	typedef Type value_type;
	typedef const value_type* pointer;
	typedef const value_type& reference;

	template<typename Other>
	struct rebind {
		typedef ConstTraits<Other> other;
	};
};

template<typename Traits>
class ListIterator {
public:
	typedef std::bidirectional_iterator_tag iterator_category;
	typedef std::ptrdiff_t difference_type;
	typedef difference_type distance_type;
	typedef typename Traits::value_type value_type;
	typedef typename Traits::pointer pointer;
	typedef typename Traits::reference reference;

private:
	typedef ListNode<value_type> Node;
	typedef typename Traits::template rebind<Node>::other NodeTraits;
	typedef typename NodeTraits::pointer NodePointer;
	typedef typename Traits::template rebind< Opaque<value_type> >::other OpaqueTraits;
	typedef typename OpaqueTraits::pointer OpaquePointer;
	NodePointer m_node;

	void increment() {
		m_node = m_node->getNext();
	}
	void decrement() {
		m_node = m_node->getPrev();
	}


public:
	explicit ListIterator(NodePointer node) : m_node(node) {
	}
	explicit ListIterator(OpaquePointer p) : m_node(reinterpret_cast<NodePointer>(p)) {
	}

	NodePointer node() {
		return m_node;
	}
	OpaquePointer opaque() const {
		return reinterpret_cast<OpaquePointer>(m_node);
	}

	bool operator==(const ListIterator& other) const {
		return m_node == other.m_node;
	}
	bool operator!=(const ListIterator& other) const {
		return !operator==(other);
	}
	ListIterator& operator++() {
		increment();
		return *this;
	}
	ListIterator operator++(int) {
		ListIterator tmp = *this;
		increment();
		return tmp;
	}
	ListIterator& operator--() {
		decrement();
		return *this;
	}
	ListIterator operator--(int) {
		ListIterator tmp = *this;
		decrement();
		return tmp;
	}
	reference operator*() const {
		return m_node->value;
	}
	pointer operator->() const {
		return &(operator*());
	}
};
}

template < typename Value, typename Allocator = DefaultAllocator<Value> >
class List : private Allocator {
	typedef ListDetail::ListNode<Value> Node;
	ListDetail::ListNodeBase list;
	typedef typename Allocator::template rebind<Node>::other NodeAllocator;

	Node* newNode(const Value& value) {
		return new (NodeAllocator(*this).allocate(1)) Node(value);
	}
	void deleteNode(Node* node) {
		node->~Node();
		NodeAllocator(*this).deallocate(node, 1);
	}
public:
	typedef Value value_type;
	typedef ListDetail::ListIterator< ListDetail::NonConstTraits<Value> > iterator;
	typedef ListDetail::ListIterator< ListDetail::ConstTraits<Value> > const_iterator;

	List() {
		list_initialise(list);
	}
	explicit List(const Allocator& allocator) : Allocator(allocator) {
		list_initialise(list);
	}
	~List() {
		for (; list.next != &list;) {
			Node* node = static_cast<Node*>(list.next);
			list.next = list.next->next;
			deleteNode(node);
		}
	}
	iterator begin() {
		return iterator(static_cast<Node*>(list.next));
	}
	iterator end() {
		return iterator(static_cast<Node*>(&list));
	}
	const_iterator begin() const {
		return const_iterator(static_cast<const Node*>(list.next));
	}
	const_iterator end() const {
		return const_iterator(static_cast<const Node*>(&list));
	}
	void push_back(const Value& value) {
		insert(end(), value);
	}
	void pop_back(const Value& value) {
		erase(--end(), value);
	}
	void push_front(const Value& value) {
		insert(begin(), value);
	}
	void pop_front(const Value& value) {
		erase(begin(), value);
	}
	iterator insert(iterator pos, const Value& value) {
		Node* node = newNode(value);
		node_link(node, pos.node());
		return iterator(node);
	}
	iterator erase(iterator pos) {
		Node* node = pos.node();
		Node* next = node->getNext();
		node_unlink(node);
		deleteNode(node);
		return iterator(next);
	}
};

template<typename Functor>
class SignalBase {
	typedef List<Functor> SignalList;
	SignalList events;

public:

	typedef Functor handler_type;
	typedef Handle< Opaque<Functor> > handler_id_type;
	typedef typename SignalList::iterator iterator;
	typedef typename SignalList::const_iterator const_iterator;
	iterator begin() {
		return events.begin();
	}
	iterator end() {
		return events.end();
	}
	const_iterator begin() const {
		return events.begin();
	}
	const_iterator end() const {
		return events.end();
	}
	handler_id_type connectFirst(const Functor& event) {
		events.push_front(event);
		return handler_id_type(begin().opaque());
	}
	handler_id_type connectLast(const Functor& event) {
		events.push_back(event);
		return handler_id_type((--end()).opaque());
	}
	bool isConnected(handler_id_type id) {
		for (iterator i = begin(); i != end(); ++i) {
			if (id.get() == i.opaque()) {
				return true;
			}
		}
		return false;
	}
	handler_id_type connectBefore(handler_id_type id, const Functor& event) {
		ASSERT_MESSAGE(isConnected(id), "SignalBase::connectBefore: invalid id");
		return events.insert(iterator(id.get()), event).opaque();
	}
	handler_id_type connectAfter(handler_id_type id, const Functor& event) {
		ASSERT_MESSAGE(isConnected(id), "SignalBase::connectAfter: invalid id");
		return events.insert(++iterator(id.get()), event).opaque();
	}
	void disconnect(handler_id_type id) {
		ASSERT_MESSAGE(isConnected(id), "SignalBase::disconnect: invalid id");
		events.erase(iterator(id.get()));
	}
};

///\brief
// It is safe to disconnect the signal handler currently being invoked.
template<typename InputIterator, typename SignalHandlerInvoke>
inline void invokeSignalHandlers(InputIterator first, InputIterator last, SignalHandlerInvoke invoke) {
	while (first != last && invoke(*first++) != SIGNAL_STOP_EMISSION) {
	}
}

class Signal0 : public SignalBase<SignalHandler> {
public:
	void operator()() const {
		invokeSignalHandlers(begin(), end(), FunctorInvoke<handler_type>());
	}
};

template<typename FirstArgument>
class Signal1 : public SignalBase< SignalHandler1<FirstArgument> > {
	typedef SignalBase< SignalHandler1<FirstArgument> > Base;
public:
	void operator()(FirstArgument a1) const {
		invokeSignalHandlers(Base::begin(), Base::end(), Functor1Invoke<typename Base::handler_type>(a1));
	}
};

template<typename FirstArgument, typename SecondArgument>
class Signal2 : public SignalBase< SignalHandler2<FirstArgument, SecondArgument> > {
	typedef SignalBase< SignalHandler2<FirstArgument, SecondArgument> > Base;
public:
	void operator()(FirstArgument a1, SecondArgument a2) const {
		invokeSignalHandlers(Base::begin(), Base::end(), Functor2Invoke<typename Base::handler_type>(a1, a2));
	}
};

template<typename FirstArgument, typename SecondArgument, typename ThirdArgument>
class Signal3 : public SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> > {
	typedef SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> > Base;
public:
	void operator()(FirstArgument a1, SecondArgument a2, ThirdArgument a3) const {
		invokeSignalHandlers(Base::begin(), Base::end(), Functor3Invoke<typename Base::handler_type>(a1, a2, a3));
	}
};

#endif
