/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   C++ template to call every registered listener function.
 *//*
 * LEGAL:   COPYRIGHT (C) 2005 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef BASE_EVENT_HH
#define BASE_EVENT_HH 1

#include <list>
#include <algorithm>
#include "base/globals.hh"

namespace base {

// Macro to define nested class.
// Functor must not hold a ref-ptr to its owner
// (would create a cycle of reference-counted pointers).
#define CLASS_EVENT_LISTENER( LISTENER_CLASS, EVENT_CLASS, OWNER_CLASS, OWNER_MEMBER )  \
class LISTENER_CLASS : public base::Event<EVENT_CLASS>::ListenerFunctor                 \
{                                                                                       \
public:                                                                                 \
             LISTENER_CLASS( OWNER_CLASS& obj ) : OWNER_MEMBER(obj) { }                 \
    virtual ~LISTENER_CLASS() { }                                                       \
    virtual void operator()( EVENT_CLASS );                                             \
                          /* EVENT_CLASS& faster but wrong if class is shptr<> */       \
private:                  /* shptr<> must never be passed as a reference */             \
    OWNER_CLASS& OWNER_MEMBER;                                                          \
};

// Macro.
#define CLASS_EVENT_LISTENER_BASIC( LISTENER_CLASS, EVENT_CLASS )                       \
class LISTENER_CLASS : public base::Event<EVENT_CLASS>::ListenerFunctor                 \
{                                                                                       \
public:                                                                                 \
             LISTENER_CLASS( void ) { }                                                 \
    virtual ~LISTENER_CLASS() { }                                                       \
    virtual void operator()( EVENT_CLASS  );                                            \
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Broadcasts events to registered listener functors.
///
/// @verbatim
///
/// Overview:
/// ---------
/// This class provides a registry for listener functors.
/// Broadcast() calls every listener.
///
/// The purpose is similar to the Chain of Responsibility design pattern,
/// but listeners are not aware of a chain nor each other.
///
/// Usage and examples:
/// -------------------
/// In general, broadcasting should be done at the very beginning
/// or very end of a function to avoid inconsistent state.
/// Event objects are optional and are passed by value to listeners.
///
/// Event<>         mEventReady;
/// Event<Message>  mEventMessage;
///
/// class ReadyListener : public Event<>::ListenerFunctor
/// {
///     virtual void operator()( Void nothing );  // Void class substitutes for intrinsic void
/// };
///
/// class MessageListener : public Event<Message>::ListenerFunctor
/// {
///     virtual void operator()( Message msg );
/// };
///
/// mEvent.Listen( new ReadyListener );  // construct and pass functor to Listen()
/// mEvent.Listen( new MessageListener );
///
/// mEvent.Broadcast( Void() );  // template restriction: simply "Broadcast()" won't compile
///
/// @endverbatim
///
template<typename EVENT=Void>  // Void, not void
class Event
{
public:
    ////////////////////////////////////////////////////////////////////////////////
    /// @brief Listener functor called when event is broadcast.
    ///
    /// Counterpart to a callback function type in C.
    ///
    class ListenerFunctor : public Shared
    {
    public:
                        ListenerFunctor( void ) { }
        virtual         ~ListenerFunctor() { }
        virtual void    operator()( EVENT event ) { }
    };

private:

#if ! DOXYGEN
// For all methods except for ctor.
#define EVENT_PROLOGUE()                                    \
{                                                           \
    /* In case Event object is persistent. */               \
    if ( UX(base::gGlobals.mExiting) ) return;              \
}
#endif

public:

    Event( void )
    {
    //EVENT_PROLOGUE();
    }

    ~Event()
    {
    EVENT_PROLOGUE();
    }

    /// Register a listener.
    void Listen( shptr<ListenerFunctor> listener )
    {
    EVENT_PROLOGUE();

        mListeners.push_front( listener );
    }

    /// Unregister a listener.
    void Unlisten( shptr<ListenerFunctor> listener )
    {
    EVENT_PROLOGUE();

        typename Listeners::iterator iter;
        iter = std::find( mListeners.begin(), mListeners.end(), listener );
        if ( iter != mListeners.end() )
        {
            mListeners.erase( iter );
        }
    }

    /// Broadcast an object to all listeners.
    /// If no arg exists, call as Broadcast( Void() ).
    void Broadcast( EVENT event )
    {
    EVENT_PROLOGUE();

        // Call every listener.
        typename Listeners::iterator iter;
        for ( iter = mListeners.begin(); iter != mListeners.end(); ++iter )
        {
            ListenerFunctor& functor = *(*iter); // REF()
            functor( event );
        }
    }

private:
    // Contain the actual functors, not copies.
    typedef std::list< shptr<ListenerFunctor> > Listeners;
    Listeners   mListeners;

#undef EVENT_PROLOGUE
};

} // namespace base

#endif // BASE_EVENT_HH
