/*
  Deferred Messaging Module
  jhaley 01/19/2011
  
  This set of classes can be used to pass messages between arbitrary objects.
  The messages are deferrable, with an optional maximum number of dispatches.
  When a destination responds to a message, either by accepting or refusing
  it, the source of the message will be notified.
*/

#ifndef deferred_messages_h__
#define deferred_messages_h__

class classDeferredMessageQueue;
class classDeferredMessage;

//
// classDeferredMessageListener
//
// Create one derived instance of this abstract class for each object that wants
// to send or receive messages.
//
class classDeferredMessageListener
{
private:
  set<classDeferredMessageQueue *> queues;
  
  // only the message queue class is allowed to do this:
  friend class classDeferredMessageQueue;
  void AddQueue(classDeferredMessageQueue *queue);
  void RemoveQueue(classDeferredMessageQueue *queue);  
  
public:
  classDeferredMessageListener();
  void ShutDown();
  virtual ~classDeferredMessageListener();
  // Return a unique name from this routine to globally identify this listener
  virtual const char *GetName() = 0;
  // Return true if you can accept the message or false otherwise 
  virtual bool CanAcceptMessage(classDeferredMessage &msg) = 0;
  // Take action on the message after accepting it. 
  virtual void AcceptMessage(classDeferredMessage &msg) = 0;
  /* Called on source after recipient acts on the message.
     The result code can be modified if desired. The value of result should
     be one of the classDeferredMessage result codes */
  virtual void MessageResult(classDeferredMessage &msg, int &result) = 0;
};

//
// classDeferredMessage
//
// This class represents a deferrable, refusable, and cancelable message between 
// two objects.
//
class classDeferredMessage
{
private:
  classDeferredMessageListener *recipient;
  classDeferredMessageListener *source;
  string message_name;
  string message_reason;
  int dispatch_count;     // number of times tried so far
  int max_dispatch_count; // maximum tries, if not -1
  
public:
  // message result codes:
  enum
  {
    RES_DISPATCHED, // recipient accepted the message
    RES_REFUSED,    // recipient refused the message
    RES_FAILED,     // message has not been accepted in max_dispatch_count tries
    RES_CANCELED    // message canceled by recipient
  };
  
  classDeferredMessage();
  classDeferredMessage(classDeferredMessageListener *src,
                       classDeferredMessageListener *dest,
                       const string &msg_name, const string &msg_reason,
                       int max_dispatches = -1);

  classDeferredMessage(const classDeferredMessage &other);

  // name and reason identify the type/purpose of the message
  string GetName();
  string GetReason();

  // recipient and source; the destination and originator of the message.
  classDeferredMessageListener *GetRecipient();
  classDeferredMessageListener *GetSource();

  // dispatching mechanics
  int  GetDispatchCount();
  int  GetMaxDispatchCount();
  void SetMaxDispatchCount(int ct);

  // AttemptDispatch will try to send the message to the recipient
  int AttemptDispatch();
  
  // Cancel is called when the recipient cancels messages, such as when it is deleted
  void Cancel();
};

//
// classNoSuchListener
//
// Exception thrown by classDeferredMessageQueue if an unknown listener is
// named in a parameter to CreateMessage.
//
class classNoSuchListener
{
};

//
// classDeferredMessageQueue
//
// This class represents a communications channel between arbitrary objects
// (an object can even listen for its own events, simply by addressing itself).
//
class classDeferredMessageQueue
{
private:
  TTimer *timer;
  list<classDeferredMessage> deferred_messages; 
  int lock_count;
  bool use_timer;
  
  map<string, classDeferredMessageListener *> listeners;
 
  // event handlers
  void __fastcall timerEvent(TObject *Sender);
  
public:
  classDeferredMessageQueue(bool p_use_timer, bool enabled, int interval);
  ~classDeferredMessageQueue();
  
  // listeners
  void AddListener(classDeferredMessageListener *listener);
  void RemoveListener(classDeferredMessageListener *listener);
  void RemoveAllListeners();
  classDeferredMessageListener *FindListener(const string &name);
  
  // messages
  classDeferredMessage CreateMessage(const string &source, const string &dest,
                                     const string &name,   const string &reason,
                                     int max_dispatch_count = -1);
  bool ScheduleMessage(classDeferredMessage &msg);
  void CancelMessagesFor(classDeferredMessageListener *recipient);
  void CancelMessagesFrom(classDeferredMessageListener *source);
  void CancelAllMessages();
  void DispatchMessages();
  
  // queue locking semantics
  void LockQueue();
  void UnlockQueue();
  bool IsLocked();

  bool IsTimerEnabled();
  void SetTimerEnabled(bool enabled);
  Cardinal GetTimerInterval();
  void SetTimerInterval(Cardinal interval);
};

#endif 

// EOF