
#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(), FunctorInvoke<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(), FunctorInvoke<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(), FunctorInvoke<typename Base::handler_type>( a1, a2, a3 ) );
}
};

#endif
