// DWBS ------------------------------------------------------------------ DWBS
//
// PLATFORM		: ALL
// PRODUCT		: BIT_DEMON
// VISIBILITY	: PUBLIC
//
// DWBS ------------------------------------------------------------------ DWBS

// PURPOSE: Clients side interface to the DemonWare messaging service.

#ifndef BD_MESSAGE_STORE_H
#define BD_MESSAGE_STORE_H

#include <bdCore/bdCore.h>
#include <bdLobby/bdLobbyErrorCode.h>
#include <bdLobby/bdLobbyCommon/bdQueryParams.h>
#include <bdLobby/bdLobbyCommon/bdQueryResult.h>
#include <bdLobby/bdMessageStore/bdLobbyMessageCompare.h>

class bdRemoteTask;
class bdRemoteTaskManager;

BD_REFERENCE(bdConnection);
BD_REFERENCE(bdLobbyMessage);

/// Client side interface to the DemonWare message management service.
/// Manages the retrieval and deletion of messages.
class bdMessageStore
{
	public:
		BD_DECLARE_NEW_AND_DELETE_OPERATORS

		enum bdMessageDeliveryMethod
		{
			BD_PULL_ONLY,
			BD_PUSH_ONLY,
			BD_PUSH_AND_PULL
		};

		~bdMessageStore();

		/// Deletes a single message from the users message store on the server.
		/// \param controllerIndex[in]	The controller index of the requester.
		/// \param messageID[in]		The ID of the message to delete.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 
		bdRemoteTask* deleteMessage(bdUByte8 controllerIndex,
									bdUInt64 messageID);

		/// Deletes messages with specified msgIDs from the users message store 
		/// on the server.
		/// \param messageIDs[in]		The IDs of the messages to delete.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 
		bdRemoteTask* deleteMessages(const bdUInt64 *messageIDs,
									 bdUInt numMessageIDs);

		/// Send a custom message to a friend.
		/// Use this method when you need to send messages that you have 
		/// designed. This is useful for message types that are specific to your
		/// title, and have not been defined by Matchmaking+.
		/// \param userIDs[in]			The User ID of the friend to send the 
		///								message to. 
		///								A maximum of 10 userIDs per request is imposed.
		/// \param numUserIDs[in]		The number of userIDs you wish to send messages to.
		/// \param payload[in]			A bdByteBuffer array containing the custom message 
		///								to send.
		/// \param deliveryMethod[in]	An enumerated value that specifies whether 
		///								to use push or pull messaging, or both.
		///								See bdMessageDeliveryMethod.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message 
		///			could not be sent, or maximum number of tasks was exceeded).
		/// \note	A BD_FRIEND_CUSTOM_MSG will be delivered to the user
		///			specified by friendId.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success.
		///			BD_NOT_A_FRIEND - if the user specified by friendID is not
		///			in the caller's friend list. 
		///			BD_USERID_BANNED - if the user specified by friendID has blocked
		///			the caller by calling bdFriends::setBlockedStatus.
		bdRemoteTask* sendMessageToUsers(const bdOnlineUserID *userIDs,
										 bdUInt numUserIDs,
										 bdByteBuffer& payload,
										 bdMessageDeliveryMethod deliveryMethod);

		/// Send a custom message to all members on a team.
		/// Use this method when you need to send messages that you have 
		/// designed. This is useful for message types that are specific to your
		/// title, and have not been defined by Matchmaking+.
		/// \param teamID[in]			The teamID of the team to send the 
		///								message to. 
		///								A maximum of 10 userIDs per request is imposed.
		/// \param payload[in]			A bdByteBuffer array containing the custom message 
		///								to send.
		/// \param deliveryMethod[in]	An enumerated value that specifies whether 
		///								to use push or pull messaging, or both.
		///								See bdMessageDeliveryMethod.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message 
		///			could not be sent, or maximum number of tasks was exceeded).
		/// \note	A BD_FRIEND_CUSTOM_MSG will be delivered to the user
		///			specified by friendId.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success.
		///			BD_NOT_A_FRIEND - if the user specified by friendID is not
		///			in the caller's friend list. 
		///			BD_USERID_BANNED - if the user specified by friendID has blocked
		///			the caller by calling bdFriends::setBlockedStatus.		
		bdRemoteTask* sendMessageToTeam(bdTeamID teamID,
										bdByteBuffer& payload,
										bdMessageDeliveryMethod deliveryMethod);

		/// Retrieves the entire contents of a selection of messages stored for
		/// the requester.  The most recent message is stored at index 0 and
		/// messages are returned sorted by their age, with the newest messages
		/// being returned first.
		/// \param	controllerIndex[in] The controller index of the requester.
		/// \param	startIndex[in]		The message index to start retrieving from.
		/// \param	maxNumMessages[in]	The maximum number of messages to retrieve
		///								from the messaging service.
		/// \param	markAsRead[in]		A bool flag to specify whether the messages
		///								returned should be marked as read.
		/// \param	deleteMessages[in]	A bool flag to specify whether messages
		///								that are retrieve should be deleted from
		///								the server.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 
		bdRemoteTask* getMessages(	bdUByte8 controllerIndex,
									bdUInt startIndex,
									bdUInt maxNumMessages,
									bdBool markAsRead = true,
									bdBool deleteMessages = false);


		/// Retrieves a users messages which match the specified message types
		/// from the server and adds them to the local message store. 
		/// The most recent message is stored at index 0 and
		/// messages are returned sorted by their age, with the newest messages
		/// being returned first.
		/// \param	msgTypes[in]		An array of bdLobbyMessageType, the message types 
		///								which will be returned by the server (if any exist in 
		///								userIDs message store).
		/// \param	numTypes[in]		The size of msgTypes.
		/// \param  maxNumMessages[in]	The maximum number of messages to retrieve.
		/// \param  getOnlyUnRead[in]	If true then query only retrieves unread messages.
		///								If false, retrieves read & unread messages.
		/// \param	markAsRead[in]		A bool flag to specify whether the messages
		///								returned should be marked as read.
		/// \param	deleteMessages[in]	A bool flag to specify whether messages
		///								that are retrieved should be deleted from
		///								the server.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 		
		bdRemoteTask* getMessagesByType(const bdLobbyMessageType *msgTypes,
										bdUInt numTypes,
										bdUInt startIndex,
										bdUInt maxNumMessages,
										bdBool getOnlyUnRead,
										bdBool markAsRead,
										bdBool deleteMessages);

		/// Retrieves the entire contents of a selection of previously un-downloaded
		/// messages stored for the requester.  The most recent message is stored at
		/// index 0 and messages are returned sorted by their age, with the newest
		/// messages being returned first.
		/// \param	controllerIndex[in] The controller index of the requester.
		/// \param	startIndex[in]		The message index to start retrieving from.
		/// \param	maxNumMessages[in]	The maximum number of messages to retrieve
		///								from the messaging service.
		/// \param	markAsRead[in]		A bool flag to specify whether the messages
		///								returned should be marked as read.
		/// \param	deleteMessages[in]	A bool flag to specify whether messages
		///								that are retrieve should be deleted from
		///								the server.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 
		bdRemoteTask* getUnreadMessages( bdUByte8 controllerIndex,
										 bdUInt startIndex,
										 bdUInt maxNumMessages,
										 bdBool markAsRead = true,
										 bdBool deleteMessages = false);

		/// Sets the status of a message to 'read'
		/// \param	controllerIndex[in] The controller index of the requester.
		/// \param	messageID[in]	The message to update
		/// \param	markMessageAsRead[in]	A bool flag to specify whether the message
		///								has been viewed or not.
		/// \return	A pointer to the task handle that should be pumped to completion,
		///			or BD_NULL if the operation could not be performed (message
		///			could not be sent, or maximum number of tasks was exceeded).
		/// Upon successful completion of this task, handleTask() has to be called
		/// in order to retrieve the result set.
		/// \note	When complete, the returned bdRemoteTask will specify:
		///			BD_NO_ERROR - on success. 
		bdRemoteTask* setMessageStatus(bdUByte8 controllerIndex,
									   bdUInt64 messageID,
									   bdBool markMessageAsRead);

		/// Gets the number of messages currently in the local message store
		/// \return The number of messages currently in the local message store
		bdUInt getNumMessages() const;

		/// Returns the message at index from the local message store
		/// \param index[in] The index of the local message to be retrieved
		/// \return A reference to the message
		bdLobbyMessageRef getAt(bdUInt index);

		/// Removes a message from the local message store
		/// \param index[in] The index of the local message to be removed
		/// \note This function will reorder the messages in the store.
		void removeAt(bdUInt index);

		/// Sort the local message store.
		/// The templated function allows the user to pass in a comparison
		/// functor that defines how the message are to be sorted.
		/// The default DemonWare implementation is bdLobbyMessageSort.
		/// \param comparitor[in] This comparison functor that compares
		///                       bdLobbyMessages.
		/// \note See bdSort for more information on using comparison functors.
		template <typename COMPARISON_FUNCTOR>
		void sortMessages(COMPARISON_FUNCTOR comparitor);

		/// Clears all the messages that are stored locally.
		/// This function clears the local store of all messages,
		/// both push and pull.
		void clearMessages();

		/// Handles a finished task.
		/// The specified task has to be created by the message manager
		/// using one of the  functions above. Objects of type bdQueryResult
		/// can be specified to handle result sets returned from the server.
		/// \param remoteTask[in] A pointer to the remote task that requires
		///                       handling
		/// \return - True if the task was successfully handled
		///			- False otherwise, call getErrorCode() to get the error
		///           condition
		bdBool handleTask(const bdRemoteTask *remoteTask);

		/// Return the error code of the last operation that failed.
		/// \return The last error code
		bdLobbyErrorCode getErrorCode() const;
	
	private:

		bdRemoteTask* sendMessage(const bdEntityID *entityIDs,
								  bdUInt numUserIDs,
								  bdByteBuffer& payload,
								  bdMessageDeliveryMethod deliveryMethod,
								  bdBool isTeam);

	protected:

		friend class bdLobbyServiceImpl;

		/// Note: never call this constructor directly, use bdLobbyService::getMessageManager() instead.
		bdMessageStore();

		/// Sets the message manager's task manager.
		void setRemoteTaskManager(bdRemoteTaskManager *const remoteTaskManager);

		bdBool createMessage(bdBitBufferRef buffer);

		bdBool isUniqueMsgID(bdUInt64 msgID);

		bdLobbyErrorCode m_errorCode;

		bdRemoteTaskManager *m_remoteTaskManager;

		/// An array of received messages
		bdArray<bdLobbyMessageRef> m_messages;
};

#include <bdLobby/bdMessageStore/bdMessageStore.inl>

#endif // BD_MESSAGE_STORE_H
