#ifndef _DMMONITOR_H
#define _DMMONITOR_H

#include "ErrorHandler.h"
#include "DataManager.h"
#include "DmGroup.h"
#include "DynamicArray.h"
#include "TaskSynchronizer.h"

extern "C" 
{
#  include "switch.h"
};


class MicroApp;

/*
CLASS 
DmMonitor

DESCRIPTION
DmMonitor monitors "command" data manager items for user input, and 
processes input.

AUTHOR
Tom O'Reilly
*/
class DmMonitor : public ErrorHandler
{
  public:

  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] name: application name
  // [input] app: Parent MicroApp
  DmMonitor(const char *name, MicroApp *app);
  
  ~DmMonitor();

  ///////////////////////////////////////////////////////////////////
  // Start consumer and provider items. Process accordingly when item changes
  int run();


  ///////////////////////////////////////////////////////////////////
  // Return TRUE if any monitored DM items have changed
  MBool itemsChanged();

  ///////////////////////////////////////////////////////////////////
  // Return TRUE if specified DmObject item has changed
  // [input] dmObject: DmObject to be checked for change
  MBool itemChanged(DmObject *dmObject);

  ///////////////////////////////////////////////////////////////////
  // Return TRUE if specified DM_Item has changed
  // [input] dmItem: DM_Item to be checked for change
  MBool itemChanged(DM_Item dmItem);
  
  typedef void (DmMonitor::*CallbackMethod)();
  
  ///////////////////////////////////////////////////////////////////
  // Add DmObject to monitored list
  // [input] dmObject: DmObject to be monitored
  // [input] callback: Function to call when request is written to dmObject
  int addMonitoredItem(DmObject *dmObject,
		       CallbackMethod callback = NULL);

  ///////////////////////////////////////////////////////////////////
  // Add DM_Item to monitored list
  // [input] dmItem: DM_Item to be monitored
  // [input] callback: Function to call when dmObject changes
  int addMonitoredItem(DM_Item dmItem,
		       CallbackMethod callback = NULL);

  protected:


  ///////////////////////////////////////////////////////////////////
  // Start consuming monitored Datamanager items
  virtual int startMonitoring();

  ///////////////////////////////////////////////////////////////////
  // cmdGroupCallback() is called once when one or more "command" DM items 
  // in the monitored group is updated. Override this method if you want
  // to process all item changes at once (instead of the "item callback" 
  // method)
  virtual int cmdGroupCallback();

  ///////////////////////////////////////////////////////////////////
  // Process micro reset (when sync sem is given by MicroApp)
  virtual int handleResetSemaphore();

  ///////////////////////////////////////////////////////////////////
  // Return status of micro's power switch
  virtual switchStatus powerSwitchStatus();
  
  ///////////////////////////////////////////////////////////////////
  // Monitored Datamanger items
  DmGroup *_monitoredGroup;

  const char *_name;
  MicroApp *_app;

  SEM_ID _dmUpdateSem;
  SEM_ID _powerReqSem;
  
  switchEntry _dconSwitch;
  
  MBool _callbacksDefined;

  private:

  int invokeCallbacks();

  ///////////////////////////////////////////////////////////////////
  // MonitoredItem holds pointers to Datamanager item and callback
  // member function  
  struct MonitoredItem
  {
    // Monitored Datamanager item
    DmObject *dmObject;

    // Pointer to callback
    void (DmMonitor::*callback)();
  };

  // Array of monitored items
  DynamicArray _monitoredItems;
  
};


#endif

