#include <stdlib.h>
#include <values.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Separator.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/Frame.h>
#include <Vk/VkErrorDialog.h>
#include "RovNav.h"
#include "TableForm.h"
#include "DmErrno.h"
#include "tiburon.h"
#include "emergency.h"

#define dprintf if (debug) fprintf


RovNav::RovNav(const char *name, Widget parent)
  : DmGuiObject(name, parent)
{
  _baseWidget = 
    XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
		   XmNorientation, XmVERTICAL,
		   NULL);

  installDestroyHandler();

  Widget label = 
    XtVaCreateManagedWidget("rovNavLabel", xmLabelWidgetClass, baseWidget(),
			    NULL);

  Widget button;
  Widget mgr;


  _armButton = 
    XtVaCreateManagedWidget("armButton", xmToggleButtonWidgetClass, 
			    baseWidget(),
			    NULL);
  
  XtAddCallback(_armButton, XmNvalueChangedCallback,
		&RovNav::vbFloodArmCallback,
		(XtPointer )this);

  const int Columns = 2;

  mgr = XtVaCreateWidget("mgr", xmRowColumnWidgetClass, baseWidget(),
			 XmNpacking, XmPACK_COLUMN,
			 XmNnumColumns, Columns,
			 XmNorientation, XmVERTICAL,
			 NULL);

  // Column 1
  _vbFloodButton = 
    XtVaCreateManagedWidget("vbFlood", xmPushButtonWidgetClass, 
			    mgr,
			    NULL);

  XtAddCallback(_vbFloodButton, XmNactivateCallback,
		&RovNav::vbFloodButtonCallback, (XtPointer )this);

  button = 
    XtVaCreateManagedWidget("getVbLevel", xmPushButtonWidgetClass, 
			    mgr,
			    NULL);

  XtAddCallback(button, XmNactivateCallback,
		&RovNav::vbButtonCallback, (XtPointer )this);

  button = 
    XtVaCreateManagedWidget("getBattery", xmPushButtonWidgetClass, 
			    mgr,
			    NULL);

  XtAddCallback(button, XmNactivateCallback,
		&RovNav::batteryButtonCallback, (XtPointer )this);

  button = 
    XtVaCreateManagedWidget("getDepth", xmPushButtonWidgetClass, 
			    mgr,
			    NULL);

  XtAddCallback(button, XmNactivateCallback,
		&RovNav::depthButtonCallback, (XtPointer )this);

  button = 
    XtVaCreateManagedWidget("test", xmPushButtonWidgetClass, 
			    mgr,
			    NULL);

  XtAddCallback(button, XmNactivateCallback,
		&RovNav::testButtonCallback, (XtPointer )this);


  // Column 2
  _vbFloodStatus = 
    XtVaCreateManagedWidget("vbFloodStatus", xmLabelWidgetClass, 
			    mgr, 
			    NULL);

  _vbLevel = 
    XtVaCreateManagedWidget("vbLevel", xmLabelWidgetClass, 
			    mgr, NULL);

  _battery = 
    XtVaCreateManagedWidget("battery", xmLabelWidgetClass, 
			    mgr, NULL);

  _depth = 
    XtVaCreateManagedWidget("depth", xmLabelWidgetClass, 
			    mgr, NULL);

  _testResult = 
    XtVaCreateManagedWidget("testResult", xmLabelWidgetClass, 
			    mgr, NULL);

  XtManageChild(mgr);

  _command = 
    XtVaCreateManagedWidget("command", xmLabelWidgetClass, baseWidget(),
			    NULL);

  _reply = 
    XtVaCreateManagedWidget("reply", xmLabelWidgetClass, baseWidget(),
			    NULL);


  char itemName[MaxDmNameLen];
  strcpy(itemName, TIBURON_DM_PREFIX);
  char *namePtr = itemName + strlen(itemName);

  strcpy(namePtr, TEST_ERS_COMS_LINK_CMD_DM);
  _dmTestCmd = new DmEmptyObject(itemName);

  if (addDmObject(_dmTestCmd, DmProvideFlag) == -1)
    return;

  strcpy(namePtr, ERS_COMS_LINK_STATUS_DM);
  _dmTestResult = new DmBooleanObject(itemName);

  if (addDmObject(_dmTestResult, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, FLOOD_VB_EMERGENCY_ARM_CMD_DM);
  _dmVbFloodArm = new DmBooleanObject(itemName);

  if (addDmObject(_dmVbFloodArm, DmProvideFlag | DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, FLOOD_VB_EMERGENCY_RUN_CMD_DM);
  _dmVbFloodCmd = new DmEmptyObject(itemName);

  if (addDmObject(_dmVbFloodCmd, DmProvideFlag) == -1)
    return;

  strcpy(namePtr, FLOOD_VB_EMERGENCY_RUNNING_DM);
  _dmVbFloodStatus = new DmBooleanObject(itemName);

  if (addDmObject(_dmVbFloodStatus, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, REPORT_ERS_VB_LEVEL_CMD_DM);
  _dmGetVbLevel = new DmEmptyObject(itemName);

  if (addDmObject(_dmGetVbLevel, DmProvideFlag) == -1)
    return;

  strcpy(namePtr, EMERGENCY_ERS_VB_LEVEL_MM_DM);
  _dmVbLevel = new DmFlt32Object(itemName);

  if (addDmObject(_dmVbLevel, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, REPORT_ERS_BATTERY_CMD_DM);
  _dmGetBattery = new DmEmptyObject(itemName);

  if (addDmObject(_dmGetBattery, DmProvideFlag) == -1)
    return;

  strcpy(namePtr, EMERGENCY_ERS_BATTERY_LIFE_DM);
  _dmBattery = new DmFlt32Object(itemName);

  if (addDmObject(_dmBattery, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, REPORT_ERS_DEPTH_CMD_DM);
  _dmGetDepth = new DmEmptyObject(itemName);

  if (addDmObject(_dmGetDepth, DmProvideFlag) == -1)
    return;

  strcpy(namePtr, EMERGENCY_ERS_DEPTH_METERS_DM);
  _dmDepth = new DmFlt64Object(itemName);

  if (addDmObject(_dmDepth, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, EMERGENCY_ERS_ROVNAV_CMD_DM);
  _dmCommand = new DmStringObject(itemName, ROVNAV_BUF_LEN);
  if (addDmObject(_dmCommand, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, EMERGENCY_ERS_ROVNAV_REPLY_DM);
  _dmReply = new DmStringObject(itemName, ROVNAV_BUF_LEN);
  if (addDmObject(_dmReply, DmConsumeFlag) == -1)
    return;

  if (setConsumePeriod(AperiodicGuaranteed) == -1)
    return;

  _prevVbFloodArm = 999;
  _prevVbFloodStatus = 999;
  _prevVbLevel = -1.;
  _prevBattery = -1.;
  _prevDepth = -1.;
  _prevTestResult = 999;
  strcpy(_prevCommand, "");
  strcpy(_prevReply, "");

  updateGui();
}


RovNav::~RovNav()
{
}


void RovNav::updateGui(DM_Item handle)
{
  MBool boolVal;
  Flt32 flt32Val;
  Flt64 flt64Val;
  DM_Time t;
  Errno err;
  XmString xmstr;
  char buf[100];
  char buf2[50];

  if ((err = _dmTestResult->read(&boolVal, &t)) != SUCCESS) {
  }
  else if (boolVal != _prevTestResult) {
    if (boolVal) 
      strcpy(buf, "OK");
    else
      strcpy(buf, "FAILED");

    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_testResult, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    _prevTestResult = boolVal;
  }

  if ((err = _dmVbFloodArm->read(&boolVal, &t)) != SUCCESS) {
  }
  else if (boolVal != _prevVbFloodArm) {
    if (boolVal) {
      XtVaSetValues(_armButton, XmNset, True, NULL);
      XtSetSensitive(_vbFloodButton, True);
      XtSetSensitive(_vbFloodStatus, True);
    }
    else {
      XtVaSetValues(_armButton, XmNset, False, NULL);
      XtSetSensitive(_vbFloodButton, False);
      XtSetSensitive(_vbFloodStatus, False);
    }
    _prevVbFloodArm = boolVal;
  }

  if ((err = _dmVbFloodStatus->read(&boolVal, &t)) != SUCCESS) {
  }
  else if (boolVal != _prevVbFloodStatus) {
    if (boolVal)
      strcpy(buf, "Running");
    else
      strcpy(buf, "Stopped");
    
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_vbFloodStatus, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    _prevVbFloodStatus = boolVal;
  }

  if ((err = _dmVbLevel->read(&flt32Val, &t)) != SUCCESS) {
  }
  else if (flt32Val != _prevVbLevel) {
    sprintf(buf, "%.0f mm", flt32Val);
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_vbLevel, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    _prevVbLevel = flt32Val;
  }

  if ((err = _dmBattery->read(&flt32Val, &t)) != SUCCESS) {
  }
  else if (flt32Val != _prevBattery) {
    sprintf(buf, "%.2f hrs", flt32Val);
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_battery, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    _prevBattery = flt32Val;
  }

  if ((err = _dmDepth->read(&flt64Val, &t)) != SUCCESS) {
  }
  else if (flt64Val != _prevDepth) {
    sprintf(buf, "%.1f meters", flt64Val);
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_depth, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    _prevDepth = flt32Val;
  }

  if ((err = _dmCommand->read(buf2, &t)) != SUCCESS) {
  }
  else if (strcmp(buf, _prevCommand)) {
    sprintf(buf, "Command:   %s", buf2);
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_command, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    strncpy(_prevCommand, buf2, sizeof(_prevCommand));
  }

  if ((err = _dmReply->read(buf2, &t)) != SUCCESS) {
  }
  else if (strcmp(buf, _prevReply)) {
    sprintf(buf, "Reply:   %s", buf2);
    xmstr = XmStringCreateSimple(buf);
    XtVaSetValues(_reply, XmNlabelString, xmstr, NULL);
    XmStringFree(xmstr);
    strncpy(_prevReply, buf2, sizeof(_prevReply));
  }
}



void RovNav::testButtonCallback(Widget w, XtPointer clientData,
				XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;
  obj->_dmTestCmd->write();
}


void RovNav::vbButtonCallback(Widget w, XtPointer clientData,
			      XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;
  obj->_dmGetVbLevel->write();
}


void RovNav::batteryButtonCallback(Widget w, XtPointer clientData,
				   XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;
  obj->_dmGetBattery->write();
}


void RovNav::depthButtonCallback(Widget w, XtPointer clientData,
				 XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;
  obj->_dmGetDepth->write();
}


void RovNav::vbFloodButtonCallback(Widget w, XtPointer clientData,
				 XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;
  obj->_dmVbFloodCmd->write();
}


void RovNav::vbFloodArmCallback(Widget w,
				XtPointer clientData,
				XtPointer callData)
{
  RovNav *obj = (RovNav *)clientData;

  MBool armValue;

  XmToggleButtonCallbackStruct *cb = 
    (XmToggleButtonCallbackStruct *)callData;
  
  if (cb->set)
    armValue = TRUE;
  else
    armValue = FALSE;
  
  DM_Time t;
  Errno errno;
  char errorBuf[errorMsgSize];

  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if ((errno = obj->_dmVbFloodArm->write(armValue, &t)) != SUCCESS)
  {
    sprintDmError(errno, "ReleaseControl::armCallback()", errorBuf);
    theErrorDialog->postAndWait(errorBuf);
  }
}

