#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/TextF.h>
#include <Xm/ToggleB.h>
#include <Vk/VkErrorDialog.h>
#include "DmGuiApp.h"
#include "stringUtils.h"
#include "parseUtils.h"
#include "TetherTurns.h"
#include "vehicleTurnsDM.h"
#include "DmErrno.h"
#include "Math.h"
#include "TiburonApp.h"

#define dprintf if (debug) fprintf


TetherTurns::TetherTurns(const char *name, Widget parent)
  : VkComponent(name)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);
  installDestroyHandler();

  Widget label;
  
  label = 
    XtVaCreateManagedWidget("twistLabel", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);
  

  _twist = 
    XtVaCreateManagedWidget("twist", xmTextFieldWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNleftPosition, 50,
			    NULL);
  
  label = 
    XtVaCreateManagedWidget("initialOffsetLabel", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _twist,
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);
  
  _initialOffset =
    XtVaCreateManagedWidget("initialOffset", xmTextFieldWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _twist,
			    XmNleftAttachment, XmATTACH_POSITION,
			    XmNleftPosition, 50,	
			    NULL);

  dmRovShipOffset = 
    new DmFlt32Object(ROV_SHIP_LAUNCH_ANGLE_DM);
  
  dmTurnsSum = 
    new DmFlt32Object(INITIAL_VEHICLE_TURNS_SUM_DM);
  
  dmResetTurns = 
    new DmBooleanObject(RESET_VEHICLE_TURNS_COUNT_DM);

  Errno err;
  char errorBuf[errorMsgSize];
  
  if ((err = dmRovShipOffset->startConsume(DM_ASYNC)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns, dmResetTurns->startConsume()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
    return;
  }

  if ((err = dmTurnsSum->startConsume(DM_ASYNC)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns, dmTurnsSum->startConsume()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
    return;
  }

  readValues();
}


TetherTurns::~TetherTurns()
{
}


void TetherTurns::readValues()
{
  DM_Time t;
  Errno errno;
  char errorBuf[errorMsgSize];
  char buf[512];
  
  Flt32 offset;
  if ((errno = dmRovShipOffset->read(&offset, &t)) != SUCCESS)
  {
    sprintDmError(errno, "post(), reading RovShipOffset", errorBuf);
    theErrorDialog->postAndWait(errorBuf);
  }
  else
  {
    sprintf(buf, "%.0f", offset / Math::RadsPerDeg);
    XmTextFieldSetString(_initialOffset, buf);
  }

  Flt32 twist;  
  if ((errno = dmTurnsSum->read(&twist, &t)) != SUCCESS)
  {
    sprintDmError(errno, "post(), reading TurnsSum", errorBuf);
    theErrorDialog->postAndWait(errorBuf);
  }
  else
  {
    sprintf(buf, "%.0f", twist / Math::RadsPerDeg);
    XmTextFieldSetString(_twist, buf);
  }
}


void TetherTurns::writeValues()
{
  Errno err;
  char errorBuf[errorMsgSize];

  if ((err = dmRovShipOffset->startProvide(DM_ASYNC)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns, dmRovShipOffset->startProvide()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
    return;
  }

  if ((err = dmTurnsSum->startProvide(DM_ASYNC)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns, dmTurnsSum->startProvide()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
    return;
  }

  if ((err = dmResetTurns->startProvide(DM_ASYNC)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns, dmResetTurns->startProvide()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
    return;
  }

  Boolean error = False;
  char *ptr;

  Flt32 offset;
  
  ptr = XmTextFieldGetString(_initialOffset);
  offset = atof(ptr);
  
  if (!isFloat(ptr) || (offset < -360. || offset > 360.))
  {
    sprintf(errorBuf, 
	    "\"%s\" - invalid launch offset. Must be floating point number "
	    "between -360 and +360", ptr);
    
    theErrorDialog->postAndWait(errorBuf);
    error = True;
  }
  else
    offset *= Math::RadsPerDeg;
  
  Flt32 twist;
  
  ptr = XmTextFieldGetString(_twist);
  if (!isFloat(ptr))
  {
    sprintf(errorBuf, "\"%s\" - invalid turns. Must be floating point number",
	    ptr);
    theErrorDialog->postAndWait(errorBuf);
    error = True;
  }
  else
    twist = atof(ptr) * Math::RadsPerDeg;

  if (error)
    return;
  
  DM_Time t;
  gettimeofday(&t, NULL);

  if ((err = dmRovShipOffset->write(offset, &t)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns(), dmRovShipOffset->write()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
  }

  if ((err = dmTurnsSum->write(twist, &t)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::dmTurnsSum(), dmRovShipOffset->write()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
  }
  
  if ((err = dmResetTurns->write(TRUE, &t)) != SUCCESS)
  {
    sprintDmError(err, "RovCompass::resetTurns(), dmResetTurns->write()", 
		  errorBuf);

    theErrorDialog->postAndWait(errorBuf);
  }

  dmRovShipOffset->stopProvide();
  dmTurnsSum->stopProvide();
  dmResetTurns->stopProvide();
}



Widget TetherTurnsDialog::createDialog(Widget parent)
{
  Widget base = VkGenericDialog::createDialog(parent);
  _info = new TetherTurns("tetherTurns", base);
  _info->show();
  _showOK = _showApply = _showCancel = True;
  return base;
}


Widget TetherTurnsDialog::post(const char *msg,
			       XtCallbackProc okCB,
			       XtCallbackProc cancelCB,
			       XtCallbackProc applyCB,
			       XtPointer clientData,
			       const char *helpString,
			       VkSimpleWindow *parent)
{
  if (_info)
    _info->readValues();
  
  VkDialogManager::post(msg, okCB, cancelCB, applyCB, clientData, helpString,
			parent);
}



void TetherTurnsDialog::applyCallback(Widget parent,
				      XtPointer clientData,
				      XtPointer callData)
{
  Boolean debug = ((TiburonApp *)theApplication)->debug();
  
  TetherTurnsDialog *obj = (TetherTurnsDialog *)clientData;
  obj->_info->writeValues();
}





