/************************************************************************/
/* Copyright 1998 MBARI							*/
/************************************************************************/
#ifndef _DMGUIOBJECT_H
#define _DMGUIOBJECT_H
static char DmGuiObject_h_id[] = "$Header: /u/oreilly/rov/tmacs/RCS/DmGuiObject.h,v 1.7 1998/12/18 21:07:21 oreilly Exp $";

/*
$Log: DmGuiObject.h,v $
Revision 1.7  1998/12/18 21:07:21  oreilly
Added documentation

Revision 1.6  1997/10/03 09:29:27  oreilly
*** empty log message ***

 * Revision 1.5  97/09/10  08:48:46  08:48:46  oreilly (Thomas C. O'Reilly)
 * *** empty log message ***
 * 
 * Revision 1.4  97/08/12  14:38:09  14:38:09  oreilly (Thomas C. O'Reilly)
 * Popup menu to plot object's DmObjects
 * 
 * Revision 1.3  97/03/20  12:33:46  12:33:46  oreilly (Thomas C. O'Reilly)
 * *** empty log message ***
 * 
 * Revision 1.2  96/10/28  09:13:35  09:13:35  oreilly (Thomas C. O'Reilly)
 * *** empty log message ***
 * 
*/


#include <stdio.h>
#include "Vk/VkComponent.h"
#include "Vk/VkApp.h"
#include "Vk/VkPopupMenu.h"
#include "DataManager.h"
#include "SList.h"
#include "ErrorHandler.h"
#include "Preference.h"

#define TRUE ~FALSE

#define dprintf if (debug) fprintf

#define DmGuiObjectPopupName "dmGuiObjectPopup"
#define CheckSticky True

const int Aperiodic = -1;
const int AperiodicGuaranteed = -2;

class DmGuiApp;
class PeriodicHandler;
class AperiodicHandler;

/*
CLASS 
DmGuiObject

DESCRIPTION


DmGuiObject associates one or more Data Manager items with one or more visible
GUI components (Widgets, VkComponents), which display Data Manager values, 
and in some cases allow the user to modify Data Manager values. The 
Data Manager items are contained within DmGuiObject as one or more DmObjects. 

More specifically, DmGuiObject performs the following functions: 

* Reads values from associated consumer DmObject(s) 

* Display values to user via Gui components. The display can be updated 
either at a constant periodic rate, or aperiodically. 

* Read user input to Gui components 

* Write user input values to DmObject(s) 

Typical sequence in DmGuiObject constructor: 

* Create and manage Gui components 

* Create dmObjects 

* addDmObject() - Add dmObjects to internal list 

* setConsumePeriod() - sets update method to periodic or aperiodic 

DmGuiObject is an abstract class; includes function updateGui(). 
updateGui() reads data from the contained DmObjects, and updates the Gui 
components accordingly. 

DmGuiObjects contain other data and objects, e.g. primitive C data types, 
structures, Widgets, VkComponents. In addition, DmGuiObjects can contain 
other DmGuiObjects. Graphical representation of a DmGuiObject is bounded
by the object's manager "baseWidget". In some cases, might want an 
aperiodicically-updated DmGuiObject (e.g. an alarm light) to be contained 
within a periodically-updated DmGuiObject (e.g. the ERS DCON display). 

DmGuiObjects are "registered" with either the PeriodicHandler or 
AperiodicHandler (contained in TiburonApp), when 
DmGuiObject::setConsumeRate() is called. If periodic, PeriodicHandler calls
the object's updateGui() function at the requested rate. If aperiodic, 
updateGui() will be called by AperiodicHandler when new data for one of 
the contained DmObjects becomes available. 


AUTHOR
Tom O'Reilly
*/
class DmGuiObject : public VkComponent, public ErrorHandler {
  friend class PeriodicHandler;
  friend class AperiodicHandler; 

  public:

  DmGuiObject(const char *name, Widget parent);

  ~DmGuiObject();

  virtual const char *className() 
  {
    return "DmGuiObject";
  }
  
  ///////////////////////////////////////////////////////////////////
  // Set consume period for all consumer DmObject(s) in DmGuiObject
  // [input] millisec: Consumer period in milliseconds, or one of the
  // values 'Aperiod' or 'AperiodicGuaranteed'
  virtual int setConsumePeriod(
			       int millisec
			       );

  ///////////////////////////////////////////////////////////////////
  // Return consume period for all consumer DmObject(s) in DmGuiObject
  // in milliseconds
  virtual int getConsumePeriod()
  {
    return _consumePeriod;
  }
  
  ///////////////////////////////////////////////////////////////////
  // Read DmObject(s), update Gui components based on new DM values 
  // (either from periodic timeout or aperiodic arrival of new data)
  // [input] handle: If consume period is Aperiodic or AperiodicGuaranteed,
  //       this is DM handle of item which changed.
  virtual void updateGui(
			 DM_Item handle = 0 // i: DM handle which changed
			                    // (non-null for aperiodic 
                                            // only)
			 ) 
  {
  }
  

  ///////////////////////////////////////////////////////////////////
  // Receive update information from another DmGuiObject
  virtual void updateFromPeer(
			      DmGuiObject *peer,
			      void *clientData
			      )
  {
  }

  ///////////////////////////////////////////////////////////////////
  // Start i/o from DmObject(s)
  virtual int startDm();
  
  ///////////////////////////////////////////////////////////////////
  // Stop i/o from DmObject(s)
  virtual int stopDm();
  
  ///////////////////////////////////////////////////////////////////
  // (Re)start provider DmObjects
  virtual int startProvide();

  ///////////////////////////////////////////////////////////////////
  // (Re)start consumer DmObjects
  virtual int startConsume();

  ///////////////////////////////////////////////////////////////////
  // Stop provider DmObjects
  virtual int stopProvide();

  ///////////////////////////////////////////////////////////////////
  // Stop consuming dmObjects (except those that are consumed by a 
  // sticky consumer, if checkSticky == True).
  virtual int stopConsume(Boolean checkSticky = False);

  ///////////////////////////////////////////////////////////////////
  // Return TRUE if provider DmObjects are enabled, else FALSE
  MBool provideEnabled()
  {
    return _provideEnabled;
  }
  
  ///////////////////////////////////////////////////////////////////
  // Return TRUE if consumer DmObjects are enabled, else FALSE
  MBool consumeEnabled()
  {
    return _consumeEnabled;
  }
  
  ///////////////////////////////////////////////////////////////////
  // Enable writing user input to DmObject(s)
  virtual void enableUserInput()  // was pure
  {
  }
  

  ///////////////////////////////////////////////////////////////////
  // Disable writing user input to DmObject(s)
  virtual void disableUserInput() // was pure
  {
  }
  

  ///////////////////////////////////////////////////////////////////
  // Pointer to cooperating DmGuiObject
  DmGuiObject *peer()
  {
    return _peer;
  }

  ///////////////////////////////////////////////////////////////////
  // Return number of consumers
  int nConsumers()
  {
    return _consumerDmObjectList.length();
  }
  

  ///////////////////////////////////////////////////////////////////
  // Return number of providers
  int nProviders()
  {
    return _providerDmObjectList.length();
  }  

  ///////////////////////////////////////////////////////////////////
  // Return TRUE if this is a "sticky" consumer, else FALSE
  Boolean stickyConsumer()
  {
    return _stickyConsumer;
  }
  
  ///////////////////////////////////////////////////////////////////
  // Specify whether this is a "sticky" consumer
  void setStickyConsumer(Boolean value);
  
  ///////////////////////////////////////////////////////////////////
  // Return TRUE if DM_Item is consumed by this DmGuiObject, else FALSE
  Boolean consumes(DM_Item dmItem);

  ///////////////////////////////////////////////////////////////////
  // Load preferences
  virtual int loadPreferences(DynArray<Preference *> *preferences, 
			      char *errorBuf);

  ///////////////////////////////////////////////////////////////////
  // Save preferences
  virtual int savePreferences(DynArray<Preference *> *preferences,
			      char *errorBuf);
  
  protected:

  ///////////////////////////////////////////////////////////////////
  // Add DmObject to be consumed and/or provided
  // [input] dmObject: DmObject to be consumed and/or provided
  // [input] flags: Combination of DmConsumeFlag and DmProvideFlag
  int addDmObject(
		  DmObject *dmObject, 
		  DmRoleFlags flags
		  );
  
  ///////////////////////////////////////////////////////////////////
  // Delete specified DmObject, after removing it from consumed and
  // provided lists.
  void deleteDmObject(
		      DmObject *dmObject
		      );

  ///////////////////////////////////////////////////////////////////
  // Exit application gracefully
  void exit(int status);
  
  ///////////////////////////////////////////////////////////////////
  // Get pointer to DmGuiApp
  static DmGuiApp *getDmGuiApp(); 

  Period _consumePeriod;
  Period _providePeriod;

  ///////////////////////////////////////////////////////////////////
  // Indicates if consumers and providers are active
  MBool _provideEnabled;
  MBool _consumeEnabled;  

  ///////////////////////////////////////////////////////////////////
  // Cooperating DmGuiObject (often is NULL)
  DmGuiObject *_peer;

  ///////////////////////////////////////////////////////////////////
  // Post menu showing options in response to button press
  virtual void postOptions(XEvent *event);

  ///////////////////////////////////////////////////////////////////
  // Menu posted by postOption  
  static VkPopupMenu *_popupMenu;

  ///////////////////////////////////////////////////////////////////
  // Event handler to display options.
  // Must be accessible to subclasses.
  static void eventHandler(Widget w, XtPointer clientData, XEvent *event);

  ///////////////////////////////////////////////////////////////////
  // If this is a "sticky" consumer, other DmGuiObjects won't call 
  // DmObject::stopConsumer() on any DmObjects contained in this DmGuiObject.
  Boolean _stickyConsumer;
  
  private:
  
  ///////////////////////////////////////////////////////////////////
  // Linked lists of provider and consumer DmObjects
  SList<DmObject *> _providerDmObjectList;
  SList<DmObject *> _consumerDmObjectList;  

  // Convert millisecs to Period
  Period millisecToPeriod(int millisec);

  // Return TRUE if millisec is valid, else FALSE
  MBool validMillisec(int millisec);

  ///////////////////////////////////////////////////////////////////
  // Add options to popup menu
  void addOptionItems();

  static void plotDmItemCallback(Widget w,
				 XtPointer clientData,
				 XtPointer callData);
};


#endif
