/*
 * Modification History
 *
 * 2003-July-20    Jason Rohrer
 * Created.
 *
 * 2003-August-25   Jason Rohrer
 * Added support for registering message handler functions.
 *
 * 2003-October-7   Jason Rohrer
 * Added separate locks for handlers and receive addresses to fix deadlocks.
 *
 * 2003-December-5   Jason Rohrer
 * Added support for message utility.
 */



#ifndef LOCAL_ADDRESS_RECEIVER_INCLUDED
#define LOCAL_ADDRESS_RECEIVER_INCLUDED



#include "minorGems/network/p2pParts/OutboundChannel.h"

#include "minorGems/util/SimpleVector.h"
#include "minorGems/system/MutexLock.h"



/**
 * Class that is used interally to encapsulate information about registered
 * handler functions.
 *
 * @author Jason Rohrer.
 */
class MessageHandlerWrapper {
    public:
        int mHandlerID;
        int (*mHandlerFunction)( char *, char *, char *, void * );
        void *mExtraHandlerArgument;
    };



/**
 * A class that queues messages received on local virtual addresses.
 *
 * All calls are thread-safe.
 *
 * @author Jason Rohrer.
 */
class LocalAddressReceiver {



    public:
        
        /**
         * Constructs a receiver.
         */
        LocalAddressReceiver();

        ~LocalAddressReceiver();



        /**
         * Adds an address that this node will receive on.
         *
         * @param inAddress a virtual address to receive messages on.
         *   Must be destroyed by caller.
         */
        void addReceiveAddress( char *inAddress );



        /**
         * Removes a receive address, causing this node to stop receiving ]
         * on the address.
         *
         * @param inAddress a virtual address to stop receiving on.
         *   Must be destroyed by caller.
         */
        void removeReceiveAddress( char *inAddress );



        /**
         * Passes a received message into this receiver.
         *
         * @param inFromAddress the virtual address that the message is from.
         *   Must be destroyed by caller.
         * @param inToAddress the virtual address that the message is to.
         *   Must be destroyed by caller.
         * @param inBody the body of the message.
         *   Must be destroyed by caller.
         * @param outUtilityGenerated pointer to location where generated
         *   utility should be returned.
         *   Must be destroyed by caller.
         *
         * @return true if this message matches one of this node's
         *   virtual addresses.
         */
        char messageReceived( char *inFromAddress,
                              char *inToAddress,
                              char *inBody,
                              int *outUtilityGenerated );



        /**
         * Registers a handler function to process all locally-received
         * messages.
         *
         * Thread-safe.
         *
         * All (char *) parameters passed in to handler will be destroyed by
         * caller and therefore should not be destroyed by the handler.
         *
         * The extra (void *) argument can be used to encapsulate any
         * additional state that should be associated with a particular
         * handler.  For example, it could be a pointer to a C++ object that
         * is "unwrapped" by casting inside the handler function.
         *
         * @param inHandlerFunction a pointer to the handler function.
         *   This function must return the utility generated by the handle
         *   and take the following arguments:
         *   (char *inFromAddress, char *inToAddress, char *inBody,
         *    void *inExtraArgument ).
         * @param inExtraHandlerArgument pointer to an extra argument to be
         *   passed in to the handler function each time it is called.
         *   Must be destroyed by caller after the handler is removed.
         *
         * @return an ID for this handler that can be used to remove it later.
         */
        int addMessageHandler(
            int (*inHandlerFunction)( char *, char *, char *, void * ),
            void *inExtraHandlerArgument );



        /**
         * Removes a message handler so that it will no longer process
         * locally-received messages.
         *
         * Thread-safe.
         *
         * @param inHandlerID the ID of the handler as returned by
         *   a call to muteAddMessageHandler.
         */
        void removeMessageHandler( int inHandlerID );

        

        /**
         * Gets the number of received messages that are waiting.
         *
         * Note that this function is only useful if no message handlers are
         * registered.  If handlers are registered, they will process all
         * messages and this function will always return 0.
         *
         * @param inAddress the virtual address to check for waiting messages.
         *   Must be destroyed by caller.
         *
         * @return the number of received messages.
         */
        unsigned int getWaitingMessageCount( char *inAddress );



        /**
         * Gets received messages.
         *
         * Note that this function is only useful if no message handlers are
         * registered.  If handlers are registered, they will process all
         * messages and this function will always return 0 messages and empty
         * arrays.
         *
         * @param inAddress the virtual address to get waiting messages for.
         *   Must be destroyed by caller.
         * @param inNumMessages the number of messages to get.
         * @param outMessages pointer to location where an array of
         *   messages should be returned.
         *   Returned array and messages must be destroyed by caller.
         * @param outFromAddresses pointer to location where an array of
         *   from addresses, one per message should be returned.
         *   Returned array and addresses must be destroyed by caller.
         *
         * @return the number of messages being returned (may be less
         *   than inNumMessages if fewer messages are available).
         */
        unsigned int getReceivedMessages( char *inAddress,
                                          unsigned int inNumMessages,
                                          char ***outMessages,
                                          char ***outFromAddresses );

        

    protected:
        // separate locks needed here so that a handler can
        // call an add/remove address function without deadlocking
        MutexLock *mHandlerLock;
        MutexLock *mReceiveAddressLock;

        SimpleVector<char *> *mAddressVector;

        int mNextFreeHandlerID;
        SimpleVector<MessageHandlerWrapper *> *mMessageHandlerVector;

        SimpleVector< SimpleVector<char *>* > *mMessageQueueVector;
        SimpleVector< SimpleVector<char *>* > *mFromAddressQueueVector;
        


        /**
         * Finds the index of an address in our vectors.
         *
         * Not thread-safe.
         *
         *
         * @param inAddress the virtual address to find the index of.
         *   Must be destroyed by caller.
         *
         * @return the index, or -1 if the address is not found.
         */
        int findAddressIndex( char *inAddress );

        
        
    };



#endif
