// ********************************************************************
// *
// * (c) Copyright 2006 Tupitskiy Dmitriy Petrovitch
// * ALL RIGHTS RESERVED 
// *
// ********************************************************************

//---------------------------------------------------------------------
#ifndef __typedmsg_H__
#define __typedmsg_H__
//---------------------------------------------------------------------

#include <memory>
#include <list>

#define DECLARE_TYPED_MESSAGE(TYPEDMESSAGENAME) \
    class TYPEDMESSAGENAME : \
        public Patterns::TypedMessage\
               <\
                    TYPEDMESSAGENAME\
               >\
    {\
    }

#define DECLARE_TYPED_MESSAGE_EXT(TYPEDMESSAGENAME, NOTIFICATIONFILTERPOLICY) \
    class TYPEDMESSAGENAME : \
        public Patterns::TypedMessage\
               <\
                    TYPEDMESSAGENAME,\
                    NOTIFICATIONFILTERPOLICY \
               >\
    {\
    }

namespace Patterns
{
    namespace StdPolicies
    {
        struct AcceptAll
        {
            template
            <
                class ListenerType
            >
            static bool overseeListener( ListenerType * ) { return true; }

            template
            <
                class MessageType
            >
            static bool overseeMessage( MessageType * ) { return true; }
        };

        struct DetachAlways
        {
            static bool isDetachable() { return true; }
        };
    } // namespace Private
    
    //! Fixed and extended implementation of Typed Message pattern dialect by Paul Pelletier.
    /*!
      Look at http://www.research.ibm.com/designpatterns/pubs/typed-msg.html
      for details.

      Note that Typed Message comprises all but the registration and
      notification machinery of this implementation.

      \param MessageType Specific message to introduce.
      \param NotificationFilterPolicy Notification mechanism for specifying 
                                      message delivery.
      \param DetachPolicy Regulates if the message should be detached when
                          listener is dying.
    */
    template
    <
        class MessageType,
        class NotificationFilterPolicy = StdPolicies::AcceptAll,
        class DetachPolicy             = StdPolicies::DetachAlways
    >
    class TypedMessage
    {
        typedef
            TypedMessage
            <
                MessageType,
                NotificationFilterPolicy,
                DetachPolicy
            >
            StrictMessageType;

    public:
        //! Message listener
        /*!
          Performs registration of message listener instance at the message's
          internal registry. Removes message listener instance when it's being
          deleted.

          It's a mixin class to be added as a parent class to message listener.
          In the message listener \a acceptMessage virtual method
          must be overridden.
        */
        class Listener
        {
        public:
            //! Registers message listerner at the internal registry of the message
            Listener()
            {
                StrictMessageType::attach(this);
            }

            //! Removes message listerner from the internal registry of the message
            ~Listener()
            {
                if ( DetachPolicy::isDetachable() )
                {
                    StrictMessageType::detach(this);
                }
            }

            //! Reaction on the MessageType class instance
            virtual void acceptMessage( const MessageType & ) = 0;
        };

        //! Perform multicast
        void notify ()
        {
            MessageType::notify(this);
        }
    private:
        friend class Listener;

        /*!
          inner Singleton patterns implementation.
          Failed to use Loki::SingletonHolder template due to
          Builder 5.0 poor template instatiation mechanism.

          \bug Issue on 4 bytes memory leak on each message. The only way out was to use
          Loki::SingletonHolder, but the approach failed. The problem is that
          we can't use here static object declaration, as it can be destroyed
          before message listener object destructor invoked.
          So the way out implemented here is the heap memory usage.
        */
        typedef
            std::list<Listener *>
            ListenerList;

        //! Holds an internal message's registry of listeners
        static ListenerList &getRegistry()
        {
            static std::auto_ptr<ListenerList> holder(new ListenerList);
            return * holder.get();
        }
        
        //! Register message Listener at the internal message's registry
        /*!
          \param aListener Listener to register.
        */
        static void attach( Listener *listener )
        {
            getRegistry().push_back( listener );
        }

        //! Remove message Listener from the internal message's registry
        /*!
          \param aListener Listener to remove.
        */
        static void detach( Listener *listener )
        {
            ListenerList &registry( getRegistry() );

            registry.erase( std::find( registry.begin(),
                                       registry.end(),
                                       listener ) );
        }

        //! MessageType class instance multicast implementation
        static void notify( StrictMessageType *message )
        {
            for ( ListenerList::iterator listener = getRegistry().begin();
                  listener != getRegistry().end(); ++ listener)
            {
                MessageType &refMessage( * static_cast< MessageType * >(message) );
                                
                if ( NotificationFilterPolicy::overseeListener( *listener )
                     && NotificationFilterPolicy::overseeMessage( & refMessage ) )
                {
                    (*listener)->acceptMessage( refMessage );
                }
            }
        }
    };

} // namespace Patterns

//---------------------------------------------------------------------
#endif  /* __typedmsg_H__ */

