#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Vk/VkRepeatButton.h>
#include <Vk/VkInfoDialog.h>
#include "PanTiltControl.h"
#include "TiburonApp.h"
#include "IviewMonitor.h"
#include "bigLeftArrow.h"
#include "bigRightArrow.h"
#include "bigUpArrow.h"
#include "bigDownArrow.h"
#include "leftArrow.h"
#include "rightArrow.h"
#include "upArrow.h"
#include "downArrow.h"

#define dprintf if (debug) fprintf

#define ArrowButtonWidth 53
#define ArrowButtonHeight 53

Pixmap PanTiltControl::_coarseLeftImage = NULL;
Pixmap PanTiltControl::_fineLeftImage = NULL;
Pixmap PanTiltControl::_coarseRightImage = NULL;
Pixmap PanTiltControl::_fineRightImage = NULL;
Pixmap PanTiltControl::_coarseUpImage = NULL;
Pixmap PanTiltControl::_fineUpImage = NULL;
Pixmap PanTiltControl::_coarseDownImage = NULL;
Pixmap PanTiltControl::_fineDownImage = NULL;

PanTiltControl::PanTiltControl(const char *name, Widget parent, 
			       IviewMonitor *monitor)
  : DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, 
				 XmNfractionBase, 50, NULL);
  installDestroyHandler();

  _monitor = monitor;
  
  char errorBuf[errorMsgSize];
  
  Pixel foreground, background;
  XtVaGetValues(_baseWidget, 
		XmNforeground, &foreground,
		XmNbackground, &background,
		NULL);
  
  Display *display = theApplication->display();
  int screenNum = DefaultScreen(display);
  
  if (!_coarseLeftImage && 
      (_coarseLeftImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   bigLeftArrowBits,
				   bigLeftArrowWidth, 
				   bigLeftArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_coarseRightImage &&
      (_coarseRightImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   bigRightArrowBits,
				   bigRightArrowWidth, 
				   bigRightArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_coarseUpImage &&
      (_coarseUpImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   bigUpArrowBits,
				   bigUpArrowWidth, 
				   bigUpArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_coarseDownImage &&
      (_coarseDownImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   bigDownArrowBits,
				   bigDownArrowWidth, 
				   bigDownArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_fineRightImage &&
      (_fineRightImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   rightArrowBits,
				   rightArrowWidth, 
				   rightArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_fineLeftImage &&
      (_fineLeftImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   leftArrowBits,
				   leftArrowWidth, 
				   leftArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_fineUpImage &&
      (_fineUpImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   upArrowBits,
				   upArrowWidth, 
				   upArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  if (!_fineDownImage && 
      (_fineDownImage = 
       XCreatePixmapFromBitmapData(display, RootWindow(display, screenNum),
				   downArrowBits,
				   downArrowWidth, 
				   downArrowHeight,
				   foreground, background,
				   DefaultDepth(display, screenNum))) 
      == False)
  {
  }

  
  _coarseUp = 
    XtVaCreateManagedWidget("coarseUp", 
			    xmPushButtonWidgetClass, _baseWidget,
			    XmNarrowDirection, XmARROW_UP,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 0, 
			    XmNbottomPosition, 10,
			    XmNleftPosition, 20,
			    XmNrightPosition, 30,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _coarseUpImage,
			    NULL);

  _fineUp = 
    XtVaCreateManagedWidget("fineUp", 
			    xmPushButtonWidgetClass, _baseWidget, 
			    XmNarrowDirection, XmARROW_UP,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 10, 
			    XmNbottomPosition, 20,
			    XmNleftPosition, 20,
			    XmNrightPosition, 30,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _fineUpImage,
			    NULL);

  _coarseRight = 
    XtVaCreateManagedWidget("coarseRight", 
			    xmPushButtonWidgetClass, _baseWidget, 
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNarrowDirection, XmARROW_RIGHT,
			    XmNtopPosition, 20,
			    XmNbottomPosition, 30,
			    XmNleftPosition, 40, 
			    XmNrightPosition, 50,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _coarseRightImage,
			    NULL);

  _fineRight = 
    XtVaCreateManagedWidget("fineRight", 
			    xmPushButtonWidgetClass, _baseWidget, 
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNarrowDirection, XmARROW_RIGHT,
			    XmNtopPosition, 20,
			    XmNbottomPosition, 30,
			    XmNleftPosition, 30,
			    XmNrightPosition, 40,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _fineRightImage,
			    NULL);

  _coarseDown = 
    XtVaCreateManagedWidget("coarseDown", 
			    xmPushButtonWidgetClass, _baseWidget, 
			    XmNarrowDirection, XmARROW_DOWN,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 40,
			    XmNbottomPosition, 50,
			    XmNleftPosition, 20,
			    XmNrightPosition, 30,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _coarseDownImage,
			    NULL);

  _fineDown = 
    XtVaCreateManagedWidget("fineDown", 
			    xmPushButtonWidgetClass, _baseWidget,
			    XmNarrowDirection, XmARROW_DOWN,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 30,
			    XmNbottomPosition, 40,
			    XmNleftPosition, 20,
			    XmNrightPosition, 30,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _fineDownImage,
			    NULL);

  _coarseLeft = 
    XtVaCreateManagedWidget("coarseLeft", 
			    xmPushButtonWidgetClass, _baseWidget,
			    XmNarrowDirection, XmARROW_LEFT,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 20,
			    XmNbottomPosition, 30,
			    XmNleftPosition, 0,
			    XmNrightPosition, 10,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _coarseLeftImage,
			    NULL);
  
  _fineLeft = 
    XtVaCreateManagedWidget("fineLeft", 
			    xmPushButtonWidgetClass, _baseWidget,
			    XmNarrowDirection, XmARROW_LEFT,
			    XmNtopAttachment, XmATTACH_POSITION,
			    XmNbottomAttachment, XmATTACH_POSITION,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNrightAttachment, XmATTACH_POSITION,
			    XmNtopPosition, 20,
			    XmNbottomPosition, 30,
			    XmNleftPosition, 10,
			    XmNrightPosition, 20,
			    XmNwidth, ArrowButtonWidth,
			    XmNheight, ArrowButtonHeight,
			    XmNlabelType, XmPIXMAP,
			    XmNlabelPixmap, _fineLeftImage,
			    NULL);

  XtAddCallback(_coarseUp, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_coarseDown, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_coarseLeft, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_coarseRight, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_fineUp, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_fineDown, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_fineLeft, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);

  XtAddCallback(_fineRight, XmNarmCallback, 
		&PanTiltControl::controlPressCallback,
		(XtPointer )this);


  XtAddCallback(_coarseUp, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_coarseDown, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_coarseLeft, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_coarseRight, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_fineUp, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_fineDown, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_fineLeft, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  XtAddCallback(_fineRight, XmNdisarmCallback, 
		&PanTiltControl::controlReleaseCallback,
		(XtPointer )this);

  char controlName[MaxControlNameLen];
  sprintf(controlName, "tmacs-%s", name);
  _iviewControl = new IviewControl(IviewPanRate | IviewTiltRate, TRUE, 
				   controlName);
  if (_iviewControl->error())
  {
    _iviewControl->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  _portLight = new PanTiltButton("portLight", _baseWidget, IviewPortLight,
				 _iviewControl, _monitor);

  XtVaSetValues(_portLight->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _coarseLeft,
		XmNleftAttachment, XmATTACH_FORM,
		NULL);

  _portLight->show();

  _portCamera = new PanTiltButton("portCamera", _baseWidget, IviewPortCamera,
				  _iviewControl, _monitor);

  XtVaSetValues(_portCamera->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _portLight->baseWidget(),
		XmNleftAttachment, XmATTACH_FORM,
		NULL);

  _portCamera->show();

  _stbdLight = new PanTiltButton("stbdLight", _baseWidget, IviewStbdLight,
				 _iviewControl, _monitor);

  XtVaSetValues(_stbdLight->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _coarseRight,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);

  _stbdLight->show();


  _stbdCamera = new PanTiltButton("stbdCamera", _baseWidget, IviewStbdCamera,
				  _iviewControl, _monitor);

  XtVaSetValues(_stbdCamera->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _stbdLight->baseWidget(),
		XmNrightAttachment, XmATTACH_FORM,
		NULL);

  _stbdCamera->show();
  
  XtAddCallback(_portLight->button(), XmNactivateCallback, 
		&PanTiltControl::deviceToggleCallback, this);

  XtAddCallback(_portCamera->button(), XmNactivateCallback, 
		&PanTiltControl::deviceToggleCallback, this);

  XtAddCallback(_stbdLight->button(), XmNactivateCallback, 
		&PanTiltControl::deviceToggleCallback, this);

  XtAddCallback(_stbdCamera->button(), XmNactivateCallback, 
		&PanTiltControl::deviceToggleCallback, this);

  TiburonApp *app = (TiburonApp *)theApplication;

  app->powerOnColors(&_onForeground, &_onBackground);
  app->faultColors(&_stolenForeground, &_stolenBackground);
  
  XtVaGetValues(_baseWidget, 
		XmNforeground, &_offForeground,
		XmNbackground, &_offBackground,
		NULL);

  _devices = _reqDevices = 0;


  DM_Item dmItem = _iviewControl->msgItem();
  _msgObj = new DmObject(&dmItem, 1);
  if (_msgObj->error())
  {
    _msgObj->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_msgObj, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(AperiodicGuaranteed) == -1)
    return;

  _statusTimer = 0;
  setButtonStates();
  startTimer();
}


PanTiltControl::~PanTiltControl()
{
  delete _iviewControl;
}


int PanTiltControl::startConsume()
{
  startTimer();
  return DmGuiObject::startConsume();
}


int PanTiltControl::stopConsume()
{
  stopTimer();
  return DmGuiObject::stopConsume();
}


void PanTiltControl::startTimer()
{
  if (!_statusTimer)
  {
    _statusTimer = 
      XtAppAddTimeOut(theApplication->appContext(), 1000,
		      &PanTiltControl::timerCallback, (XtPointer )this);  
  }
}



void PanTiltControl::stopTimer()
{
  if (_statusTimer)
  {
    XtRemoveTimeOut(_statusTimer);
    _statusTimer = NULL;
  }
}


void PanTiltControl::toggleDevice(Widget w)
{
  Boolean debug = ((TiburonApp *)theApplication)->debug();
  
  _reqDevices = _devices;
  PanTiltButton *button;
  
  if (w == _portLight->button())
  {
    button = _portLight;
  }
  else if (w == _portCamera->button())
  {
    button = _portCamera;
  }
  else if (w == _stbdLight->button())
  {
    button = _stbdLight;
  }
  else if (w == _stbdCamera->button())
  {
    button = _stbdCamera;
  }
  
  if (_reqDevices & button->iviewDevice())
    _reqDevices &= ~(button->iviewDevice());
  else
    _reqDevices |= button->iviewDevice();

  int status;
  
  if ((status = _iviewControl->setDevices(_reqDevices, IviewNoDevice)) 
      != IviewSuccess)
  {
    // Error processing here
    dprintf(stderr, 
	    "PanTiltControl::toggleDevice() - got status %d from "
	    "setDevices()\n", status);

    if (status == IviewNotStarted)
    {
      if (status == IviewNotStarted)
      {
	_reqDevices = _devices = 0;
	theInfoDialog->postAndWait("Iview not started?");
      }
    }
  }
}


void PanTiltControl::controlPressCallback(Widget w, XtPointer clientData,
					  XtPointer callData)
{
  PanTiltControl *obj = (PanTiltControl *)clientData;
  obj->startMoving(w);

  if (!obj->_iviewControl->started())
  {
    theInfoDialog->postAndWait("Iview not responding");
  }
}


void PanTiltControl::controlReleaseCallback(Widget w, XtPointer clientData,
					    XtPointer callData)
{
  PanTiltControl *obj = (PanTiltControl *)clientData;
  obj->stopMoving(w);
}


void PanTiltControl::startMoving(Widget w)
{
  Boolean debug = ((TiburonApp *)theApplication)->debug();

  dprintf(stderr, "startMoving()\n");
  
  float panRate = IviewNoChange, tiltRate = IviewNoChange;

  if (w == _coarseUp)
    tiltRate = HighTiltRate;
  else if (w == _coarseDown)
    tiltRate = -HighTiltRate;
  else if (w == _coarseLeft)
    panRate = -HighPanRate;
  else if (w == _coarseRight)
    panRate = HighPanRate;

  else if (w == _fineUp)
    tiltRate = LowTiltRate;
  else if (w == _fineDown)
    tiltRate = -LowTiltRate;
  else if (w == _fineLeft)
    panRate = -LowPanRate;
  else if (w == _fineRight)
    panRate = LowPanRate;

  _iviewControl->setPanTilt(panRate, tiltRate);
}


void PanTiltControl::stopMoving(Widget w)
{
  Boolean debug = ((TiburonApp *)theApplication)->debug();

  dprintf(stderr, "stopMoving()\n");

  float panRate = IviewNoChange, tiltRate = IviewNoChange;

  if (w == _coarseUp || w == _coarseDown 
      || w == _fineUp || w == _fineDown)
  {
    tiltRate = 0.;
  }
  else
  {
    panRate = 0.;
  }

  _iviewControl->setPanTilt(panRate, tiltRate);  
}


void PanTiltControl::updateGui(DM_Item handle)
{
  char errorBuf[errorMsgSize]; 
  Boolean debug = ((TiburonApp *)theApplication)->debug();

  dprintf(stderr, "PanTiltControl::udpateGui()\n");

  // Got an Iview message
  int msgNo;
  unsigned short newDevices;
  int msgCode;
  int status;
  IviewDevice refDevice;
  
  IviewMessage message;
  _iviewControl->getMsg(&message);

  dprintf(stderr, 
	  "PanTiltControl::updateFromPeer(), msg.id = %d, msg.devices=%d\n",
	  message.id, message.deviceMask);
  
  if ((status = _iviewControl->getMsg(&message)) != IviewSuccess)
  {
    if (status == IviewNotStarted)
    {
      dprintf(stderr, "%s - Iview not responding\n", _name);
    }
    
    _iviewControl->errorMsg(errorBuf);
    setError(errorBuf);
    prtErrorMsg();
    return;
  }

  setButtonStates();
  _devices = message.deviceMask;

  if (message.serverStarting)
    _iviewControl->initialize();
}


void PanTiltControl::deviceToggleCallback(Widget w,
					  XtPointer clientData,
					  XtPointer callData)
{
  PanTiltControl *obj = (PanTiltControl *)clientData;
  obj->toggleDevice(w);
}


void PanTiltControl::setButtonStates()
{
  _portLight->getIviewDeviceState();
  _portCamera->getIviewDeviceState();
  _stbdLight->getIviewDeviceState();
  _stbdCamera->getIviewDeviceState();
}


void PanTiltControl::timerCallback(XtPointer clientData, XtIntervalId *id)
{
  Boolean debug = False;
  dprintf(stderr, "PanTiltControl::timerCallback()\n");
  
  PanTiltControl *obj = (PanTiltControl *)clientData;

  obj->setButtonStates();
  obj->_statusTimer = NULL;
  obj->startTimer();
}


