#ifndef _IVIEWCONTROL_H
#define _IVIEWCONTROL_H
#include "ErrorHandler.h"
#include "Iview.h"
#include "DmControlSource.h"

#define NoWait NO_WAIT

struct IviewMessage
{
  int id;
  unsigned short deviceMask;
  MBool panoramic;
  MBool focusCaptured;
  MBool serverStarting;
};


/*
CLASS 
IviewControl

DESCRIPTION
IviewControl is created by Iview client. IviewControl is the
application-level interface between Iview clients and server

AUTHOR
Tom O'Reilly
*/
class IviewControl : public ErrorHandler
{
  public:

  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] axisMask: IviewAxisMask specifying axes to be controlled
  // [input] startPeriodicRequest: TRUE if client wants to start providing
  //                               periodic data
  // [input] name: Name of this control
  // [input] messageSemaphore: Semaphore for detecting new IviewMessages
  IviewControl(IviewAxisMask axisMask, 
	       MBool startPeriodicRequests,
	       const char *name,
	       SEM_ID messageSemaphore = SEM_NULL);
  
  ~IviewControl();

  int isActive(MBool *active);

  ///////////////////////////////////////////////////////////////////
  // Send AperiodicRequest specifying IviewDevices to be controlled
  // [input] deviceMask: IviewDeviceMask specifying devices to be controlled
  // [input] refDevice: Reference device
  // [input] timeoutTicks: Timeout for this request
  int setDevices(IviewDeviceMask deviceMask, 
		 IviewDevice refDevice,
		 int timeoutTicks = 60);

  ///////////////////////////////////////////////////////////////////
  // Get current IviewDevices controlled by this IviewControl
  // [output] deviceMask: IviewDeviceMask specifying IviewDevices
  // controlled by this IviewControl
  // [output] refDevice: Current reference device
  int getDevices(IviewDeviceMask *deviceMask, 
		 IviewDevice *refDevice);

  ///////////////////////////////////////////////////////////////////
  // Set sensitivity for this control
  // [input] sensitivity: IviewSensitivity 
  int setSensitivity(IviewSensitivity sensitivity, int tiemoutTicks = 60);
  
  ///////////////////////////////////////////////////////////////////
  // Set pan and tilt position
  // [input] pan: Pan position in radians
  // [input] tilt: Tilt position in radians
  int setPanTilt(float pan, 
		 float tilt, 
		 int timeoutTicks = NoWait)
  {
    return setCoords(pan, tilt, IviewNoChange, IviewNoChange, 
		     IviewNoChange,
		     timeoutTicks);
  }

  ///////////////////////////////////////////////////////////////////
  // Set focus
  // [input] focus: Focus position in ??? units
  int setFocus(float focus, 
	       int timeoutTicks = NoWait)
  {
    return setCoords(IviewNoChange, IviewNoChange, focus, IviewNoChange,
		     IviewNoChange, timeoutTicks);
  }
  
  ///////////////////////////////////////////////////////////////////
  // Set zoom
  // [input] focus: Zoom position in ??? units
  int setZoom(float zoom, 
	      int timeoutTicks = NoWait)
  {
    return setCoords(IviewNoChange, IviewNoChange, IviewNoChange, zoom,
		     IviewNoChange, timeoutTicks);
  }
  
  ///////////////////////////////////////////////////////////////////
  // Set iris
  // [input] focus: Iris value in ??? units
  int setIris(float iris, 
	      int timeoutTicks = NoWait)
  {
    return setCoords(IviewNoChange, IviewNoChange, IviewNoChange, 
		     IviewNoChange, iris, timeoutTicks);
  }


  ///////////////////////////////////////////////////////////////////
  // Set panoramic mode ON/OFF
  // [input] on: TRUE turns panoramic mode on
  int setPanoramic(MBool on, int tiemoutTicks = 60);


  ///////////////////////////////////////////////////////////////////
  // Return DM_Item for aperiodic requests
  DM_Item aperiodicRequestItem();

  ///////////////////////////////////////////////////////////////////
  // Return DM_Item for periodic requests
  DM_Item periodicRequestItem();

  ///////////////////////////////////////////////////////////////////
  // Return DM_Item for Iview status
  DM_Item statusItem();

  ///////////////////////////////////////////////////////////////////
  // Return DM_Item for Iview messages
  DM_Item msgItem();

  ///////////////////////////////////////////////////////////////////
  // Get latest message from Iview
  // [output] message: IviewMessage structure, filled in
  int getMsg(IviewMessage *message);


  ///////////////////////////////////////////////////////////////////
  // Return TRUE if connection has been made to Iview server
  MBool started()
  {
    return _started;
  }

  ///////////////////////////////////////////////////////////////////
  // Return unique identifier for this IviewControl
  int id()
  {
    return _dmControlSource->id();
  }

  ///////////////////////////////////////////////////////////////////
  // Return IviewAxisMask of this IviewControl
  IviewAxisMask axisMask();


  ///////////////////////////////////////////////////////////////////
  // Intialize IviewControl (following restart of server)
  int initialize();
  

  ///////////////////////////////////////////////////////////////////
  // Begin providing PeriodicRequest data
  int startPeriodic();
  
  protected:

  ///////////////////////////////////////////////////////////////////
  // Get connection to Iview server  
  int start();

  ///////////////////////////////////////////////////////////////////
  // Set coordinates of controlled IviewDevices
  int setCoords(float pan, 
		float tilt, 
		float focus, 
		float zoom,
		float iris, 
		int timeoutTicks = NoWait);
  
  ///////////////////////////////////////////////////////////////////
  // Process-unique id for this control 
  int _processControlId;
  
  ///////////////////////////////////////////////////////////////////
  DmControlSource *_dmControlSource;

  DmControlSource::AperiodicRequest _aperiodicRequest;
  DmControlSource::PeriodicRequest _periodicRequest;
  DmControlSource::RequestStatus _status;
  DmControlSource::Message _message;

  MBool _started;

  SEM_ID _statusSem;

  ///////////////////////////////////////////////////////////////////
  // Read status of specified request
  int requestStatus(int requestNo, int timeoutTicks);

  ///////////////////////////////////////////////////////////////////
  // Take ownership of DmControlSource by providing AperiodicRequest data
  int grabControlSource();

  unsigned short _axisMask;

  // Total # of IviewControls in this process
  int static _nIviewControls;

  // Request counter
  int _requestNo;
};

#endif
