#include <Xm/Frame.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/Label.h>
#include <Xm/ArrowB.h>
#include <Xm/Scale.h>
#include <Xm/Scale.h>
#include <xpm.h>
#include <Vk/VkErrorDialog.h>
#include "DrillSledGui.h"
#include "drillSledNames.h"
#include "powerDM.h"
#include "DmErrno.h"
#include "TiburonApp.h"
 
#define dprintf if (debug) fprintf

// 0-based index of torque select valve
#define HiLowTorqueValve (5 - 1)

XtResource DrillSledPower::_resources[] = 
{
  {
    "wobLabel",
    "WobLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _wobLabel),
    XmRImmediate, 
    "WOB transd."
  },
  {
    "torqueLabel",
    "TorqueLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _torqueLabel),
    XmRImmediate,
    "Torque transd."
  },

  {
    "rotationLabel",
    "RotationLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _rotationLabel),
    XmRImmediate,
    "Rotation sensor"
  },

  {
    "servoValveLabel",
    "ServoValveLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _servoValveLabel),
    XmRImmediate,
    "ServoValve"
  },

  {
    "hydraulicValveLabel",
    "HydraulicValveLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _hydraulicValveLabel),
    XmRImmediate,
    "HydraulicValve"
  },

  {
    "science24vLabel",
    "Science24vLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _science24vLabel),
    XmRImmediate,
    "SciencePort 24v"
  },

  {
    "camera1Label",
    "Camera1Label",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _camera1Label),
    XmRImmediate,
    "Camera 1"
  },

  {
    "camera2Label",
    "Camera2Label",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _camera2Label),
    XmRImmediate,
    "Camera 2"
  },

  {
    "ssPumpLabel",
    "SsPumpLabel",
    XmRString,
    sizeof(char *),
    XtOffset(DrillSledPower *, _ssPumpLabel),
    XmRImmediate,
    "SS Pump"
  }
};


DrillSledPower::DrillSledPower(const char *name, Widget parent,
			       DrillSledGui *drillSledGui, 
			       const char *platformName)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent,
				XmNorientation, XmVERTICAL, NULL);
  
  installDestroyHandler();

  getResources(_resources, XtNumber(_resources));

  _drillSledGui = drillSledGui;
  
  Widget label = 
    XtVaCreateManagedWidget("powerLabel", xmLabelWidgetClass, _baseWidget, 
			    NULL);
  
  Widget mgr2 = 
    XtVaCreateWidget("mgr2", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmHORIZONTAL, NULL);
  
  char itemName[MaxDmNameLen];
  DmObject::buildPrefix(itemName, platformName, PowerName, 0);

  char *namePtr = itemName + strlen(itemName);
  
  sprintf(namePtr, "%s.%s", DrillSledAppName, WobTransducerName);
  
  _wobTransducer = new PowerSwitchGui("wobTransducer", mgr2, itemName, 
				      _wobLabel, 100, 50, 500, True);
  
  _wobTransducer->show();

  sprintf(namePtr, "%s.%s", DrillSledAppName, TorqueTransducerName);
  
  _torqueTransducer = new PowerSwitchGui("torqueTransducer", mgr2, itemName,
					 _torqueLabel, 100, 50, 500, True);
  
  _torqueTransducer->show();

  
  sprintf(namePtr, "%s.%s", DrillSledAppName, RotationSensorName);
  
  _rotationSensor = 
    new PowerSwitchGui("rotationSensor", mgr2, itemName,
		       _rotationLabel, 100, 50, 500, True);

  _rotationSensor->show();

  XtManageChild(mgr2);

  mgr2 = 
    XtVaCreateWidget("mgr2", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmHORIZONTAL, NULL);


  sprintf(namePtr, "%s.%s", DrillSledAppName, ValvePackPowerName);
  
  _hydraulicValves = 
    new PowerSwitchGui("hydraulicVavle", mgr2, itemName,
		       _hydraulicValveLabel, 100, 50, 500, True);

  _hydraulicValves->show();

  sprintf(namePtr, "%s.%s", DrillSledAppName, ServoValveName);
  
  _servoValves = 
    new PowerSwitchGui("servoVavle", mgr2, itemName,
		       _servoValveLabel, 100, 50, 500, True);

  _servoValves->show();


  sprintf(namePtr, "%s.%s", DrillSledAppName, SSPumpName);
  
  _ssPump = 
    new PowerSwitchGui("ssPump", mgr2, itemName,
		       _ssPumpLabel, 100, 50, 500, True);

  _ssPump->show();

  XtManageChild(mgr2);

  mgr2 = 
    XtVaCreateWidget("mgr2", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmHORIZONTAL, NULL);

  sprintf(namePtr, "%s.%s", DrillSledAppName, Camera1Name);
  
  _camera1 =
    new PowerSwitchGui("camera1", mgr2, itemName,
		       _camera1Label, 100, 50, 500, True);

  _camera1->show();


  sprintf(namePtr, "%s.%s", DrillSledAppName, Camera2Name);
  
  _camera2 =
    new PowerSwitchGui("camera2", mgr2, itemName,
		       _camera2Label, 100, 50, 500, True);

  _camera2->show();

  sprintf(namePtr, "%s.%s", DrillSledAppName, SciencePort24vName);
  
  _science24v = 
    new PowerSwitchGui("science24v", mgr2, itemName,
		       _science24vLabel, 100, 50, 500, True);

  _science24v->show();

  XtManageChild(mgr2);
}


DrillSledPower::~DrillSledPower()
{
  delete _wobTransducer;
  delete _torqueTransducer;
  delete _rotationSensor;
  delete _servoValves;
  delete _hydraulicValves;
  delete _science24v;
  delete _camera1;
  delete _camera2;
  delete _ssPump;
}


void DrillSledPower::statusCallback(VkCallbackObject *obj,
				  void *clientData,
				  void *callData)
{
  Boolean debug = ((TiburonApp *)theApplication)->debug();
  
  dprintf(stderr, "DrillSledPower::statusCallback()\n");

  switchStatus status = (switchStatus )callData;

  if (obj == _hydraulicValves)
  {
    dprintf(stderr, "DrillSledPower::statusCallback() - valvePack status\n");

    switch (status)
    {
      case SWITCH_ON:
      case SWITCH_ON_CASCADE:
      XtSetSensitive(_drillSledGui->valveFunctions->baseWidget(), True);
      break;
      
      default:
      XtSetSensitive(_drillSledGui->valveFunctions->baseWidget(), False);
    }
  }
}


DrillSledTelemetry::DrillSledTelemetry(const char *name, Widget parent, 
				       DrillSledDm *dmObjects)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
				 XmNorientation, XmHORIZONTAL, NULL);
  
  installDestroyHandler();
  
  _dmObjects = dmObjects;

  char *tname = (char *)_dmObjects->rpm->getName();

  _drillRpm = new DmFlt32BarGraph("drillRpm", _baseWidget,
				  tname,
				  200, 0,
				  DrillSledDm::minRpm, 
				  DrillSledDm::maxRpm);

  _drillRpm->show();

  tname = (char *)_dmObjects->weightOnBit->getName();

  _weightOnBit = new DmFlt32BarGraph("weightOnBit", _baseWidget,
				     tname,
				     200, 0, 
				     0,
				     DrillSledDm::maxWOB);

  _weightOnBit->show();

  tname = (char *)_dmObjects->motorDeltaP->getName();
  _motorDeltaP = new DmFlt32BarGraph("motorDeltaP", _baseWidget,
				     tname,
				     200, 0, 
				     0,
				     DrillSledDm::maxTorque);

  _motorDeltaP->show();

  tname = (char *)_dmObjects->cutterVoltage->getName();
  _cutterVoltage = new DmFlt32BarGraph("cutterVoltage", _baseWidget,
				       tname,
				       200, 0, 
				       DrillSledDm::minCutterVolts,
				       DrillSledDm::maxCutterVolts);

  _cutterVoltage->show();
}


DrillSledTelemetry::~DrillSledTelemetry()
{
  delete _drillRpm;
  delete _weightOnBit;
  delete _motorDeltaP;
  delete _cutterVoltage;
}



DrillSledGui::DrillSledGui(const char *name, Widget parent,
			   const char *platformName)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
				 XmNorientation, XmVERTICAL, NULL);
  
  installDestroyHandler();

  _dmObjects = new DrillSledDm(platformName);

  Widget label, title;

  title = 
    XtVaCreateManagedWidget("drillSledLabel", xmLabelWidgetClass, _baseWidget,
			    NULL);

  coreHydraulics = new HydraulicSelect("hydraulicSelect", _baseWidget);
  
  coreHydraulics->show();
  
  Widget powerFrame, valveFrame, speedFrame;
  Widget mgr, mgr2;

  mgr = XtVaCreateWidget("mgr", xmRowColumnWidgetClass, _baseWidget,
			 XmNorientation, XmHORIZONTAL, NULL);

  powerFrame =
    XtVaCreateManagedWidget("powerFrame", xmFrameWidgetClass, mgr, NULL);

  power = new DrillSledPower("power", powerFrame, this, platformName);
  power->show();
  
  valveFrame =
    XtVaCreateManagedWidget("valveFrame", xmFrameWidgetClass, mgr,
			    NULL);
  
  mgr2 = XtVaCreateWidget("mgr", xmRowColumnWidgetClass, valveFrame,
			  XmNorientation, XmVERTICAL,
			  NULL);

  char dmPrefix[MaxDmNameLen];
  DmObject::buildPrefix(dmPrefix, platformName, DrillSledAppName, 0);

  valveFunctions = new ValveFunctions("valveFunctions", mgr2, 7, 1, 
				      dmPrefix, False);

  // Disable hi/low torque
  valveFunctions->valves->disableValve(HiLowTorqueValve);

  valveFunctions->show();

  // Build array of ValveControls to use in ValveSwitchMap
  int nValves = valveFunctions->nValves();
  
  if ((_valveControl = 
       (ValveControl **)malloc(nValves * sizeof(ValveControl *))) == NULL)
  {
    fprintf(stderr, 
	    "DrillSledGui::DrillSledGui() - malloc of _valveControl failed\n");
    exit(1);
  }

  for (int i = 0 ; i < nValves; i++)
    _valveControl[i] = valveFunctions->valves->valve[i];
  
  char dmName[MaxDmNameLen];
  DmObject::buildName(dmName, dmPrefix, MappedValveName, 0);
  
  _switchMap = new ValveSwitchMap("switchMap", mgr2, 2,
				  dmName,
				  nValves,
				  _valveControl);

  _switchMap->disableMap(HiLowTorqueValve);

  _switchMap->show();
  XtManageChild(mgr2);

  XtManageChild(mgr);

  mgr = XtVaCreateWidget("mgr3", xmRowColumnWidgetClass, _baseWidget,
			 XmNorientation, XmHORIZONTAL, 0);

  speedFrame = 
    XtVaCreateManagedWidget("speedFrame", xmFrameWidgetClass, mgr, NULL);

  _bitSpeedControl = new BitSpeedControl("bitSpeedCntrl", speedFrame,
					 _dmObjects);
  _bitSpeedControl->show();

  speedFrame = 
    XtVaCreateManagedWidget("speedFrame", xmFrameWidgetClass, mgr, NULL);

  waterPump = new SuctionSamplerPump("waterPump", speedFrame,
				     _dmObjects->pumpSpeed,
				     _dmObjects->pumpDirection);
				 
  waterPump->show();

  XtManageChild(mgr);

  mgr = XtVaCreateWidget("panel3", xmFormWidgetClass, _baseWidget,
			 NULL);

  _torqueSelect = 
    new DmBooleanSwitch("torqueSelect", mgr, _dmObjects->highTorqueCmd);

  XtVaSetValues(_torqueSelect->baseWidget(), 
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);

  _torqueSelect->show();

  _telemetry = new DrillSledTelemetry("telemetry", mgr, _dmObjects);

  XtVaSetValues(_telemetry->baseWidget(), 
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _torqueSelect->baseWidget(),
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);

  _telemetry->show();

  _fireControl = new FireControl("fireControl", mgr,
				 _dmObjects->fireControl);

  XtVaSetValues(_fireControl->baseWidget(), 
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _telemetry->baseWidget(),
		NULL);

  _fireControl->show();

  XtManageChild(mgr);
}


DrillSledGui::~DrillSledGui()
{
  delete _dmObjects;
  delete coreHydraulics;
  delete power;
  delete valveFunctions;
  delete waterPump;
  delete _bitSpeedControl;
  delete _switchMap;
  delete _telemetry;
  delete _fireControl;
  delete _torqueSelect;
  free((void *)_valveControl);
  
}


BitSpeedControl::BitSpeedControl(const char *name, Widget parent,
				 DrillSledDm *dmObjects)
  : DmGuiObject(name, parent)
{
  
  // Note: orientation is specified in resource file
  _baseWidget =
    XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, NULL);

  installDestroyHandler();
  
  _dmObjects = dmObjects;
  
  Widget mgr, mgr2;

  mgr = _baseWidget;

  Widget label;
  
  mgr2 = 
    XtVaCreateWidget("mgr2", xmRowColumnWidgetClass, mgr, 
		     XmNorientation, XmHORIZONTAL, NULL);
  
  label = 
    XtVaCreateManagedWidget("pumpLabel", xmLabelWidgetClass, mgr2, NULL);
			  

  XtManageChild(mgr2);
  
  mgr2 = XtVaCreateWidget("speedMgr", xmFormWidgetClass, mgr, NULL);

  _speed = XtVaCreateManagedWidget("speed", xmScaleWidgetClass, mgr2,
				   XmNorientation, XmHORIZONTAL,
				   XmNminimum, 0,
				   XmNmaximum, 100,
				   XmNvalue, 0,
				   XmNshowValue, True,
				   XmNtopAttachment, XmATTACH_FORM,
				   XmNleftAttachment, XmATTACH_FORM,
				   XmNrightAttachment, XmATTACH_FORM,
				   NULL);

  XtAddCallback(_speed, XmNdragCallback, 
		&BitSpeedControl::speedCallback,
		(XtPointer )this);

  XtAddCallback(_speed, XmNvalueChangedCallback, 
		&BitSpeedControl::speedCallback,
		(XtPointer )this);
  
  XtVaCreateManagedWidget("speedLabel", xmLabelWidgetClass, mgr2, 
			  XmNleftAttachment, XmATTACH_FORM,
			  XmNtopAttachment, XmATTACH_WIDGET,
			  XmNtopWidget, _speed,
			  NULL);
  
  XtManageChild(mgr2);
  
  Widget toggleMgr = 
    XtVaCreateWidget("toggleMgr", xmRowColumnWidgetClass, mgr,
		     XmNorientation, XmHORIZONTAL,
		     XmNradioBehavior, True,
		     XmNradioAlwaysOne, True,
		     NULL);

  _stop = XtVaCreateManagedWidget("stop", xmToggleButtonWidgetClass, toggleMgr,
				  NULL); 

  _fwd = XtVaCreateManagedWidget("fwd", xmToggleButtonWidgetClass, toggleMgr, 
				 NULL); 

  _rev = XtVaCreateManagedWidget("rev", xmToggleButtonWidgetClass, toggleMgr, 
				 NULL); 

  XtAddCallback(_stop, XmNarmCallback, &BitSpeedControl::directionCallback,
		(XtPointer )this);

  XtAddCallback(_fwd, XmNarmCallback, &BitSpeedControl::directionCallback,
		(XtPointer )this);

  XtAddCallback(_rev, XmNarmCallback, &BitSpeedControl::directionCallback,
		(XtPointer )this);

  XtManageChild(toggleMgr);
  
  XtManageChild(mgr);

  if (addDmObject(_dmObjects->bitRpmCmd, 
		  DmConsumeFlag | DmProvideFlag) == -1)
    return;

  if (addDmObject(_dmObjects->bitRotationSense, 
		  DmConsumeFlag | DmProvideFlag) == -1)
    return;

  if (addDmObject(_dmObjects->rpm, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(Aperiodic) == -1)
    return;

  _draggingSpeed = False;
  
  updateGui();
}


BitSpeedControl::~BitSpeedControl()
{
}


void BitSpeedControl::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  char errorBuf[errorMsgSize];
  Int16 speed;
  
  if (!_draggingSpeed)
  {
    if ((errno = _dmObjects->bitRpmCmd->read(&speed, &t)) != SUCCESS)
    {
      sprintDmError(errno, 
		    "SuctionSamplerPump::updateGui(), reading speed", 
		    errorBuf);

      setError(errorBuf);
      return;
    }

    XtVaSetValues(_speed, XmNvalue, speed, NULL);
  }

  Int32 direction;
  
  if ((errno = _dmObjects->bitRotationSense->read(&direction, &t)) 
      != SUCCESS)
  {
    sprintDmError(errno, 
		  "BitSpeedControl::updateGui(), reading rotation sense",
		  errorBuf);

    setError(errorBuf);
    return;
  }

  switch (direction)
  {
    case DrillSledDm::Stop:
    XtVaSetValues(_stop, XmNset, True, NULL);
    XtVaSetValues(_fwd, XmNset, False, NULL);
    XtVaSetValues(_rev, XmNset, False, NULL);
    XtSetSensitive(_fwd, True);
    XtSetSensitive(_rev, True);
    break;
    
    case DrillSledDm::Clockwise:
    XtVaSetValues(_fwd, XmNset, True, NULL);
    XtVaSetValues(_stop, XmNset, False, NULL);
    XtVaSetValues(_rev, XmNset, False, NULL);
    XtSetSensitive(_fwd, True);
    XtSetSensitive(_rev, False);
    break;

  case DrillSledDm::CounterClockwise:
    XtVaSetValues(_rev, XmNset, True, NULL);
    XtVaSetValues(_fwd, XmNset, False, NULL);
    XtVaSetValues(_stop, XmNset, False, NULL);
    XtSetSensitive(_fwd, False);
    XtSetSensitive(_rev, True);
    break;      
    
    default:
    sprintf(errorBuf, 
	    "BitSpeedControl::udpateGui(), unknown direction: %d", direction); 

    setError(errorBuf);
    return;
  }

  // Read and display actual RPM
  Flt32 rpm;
  if ((errno = _dmObjects->rpm->read(&rpm, &t)) != SUCCESS)
  {
    sprintDmError(errno, "BitSpeedControl::updateGui(), reading rpm",
		  errorBuf);

    setError(errorBuf);
    return;
  }
}


void BitSpeedControl::setSpeed(int value)
{
  DM_Time t;
  gettimeofday(&t, NULL);
  
  Int16 speed = (Int16 )value;
  Errno errno;
  char errorBuf[errorMsgSize];
  
  if ((errno = _dmObjects->bitRpmCmd->write(speed, &t)) != SUCCESS)
  {
    sprintDmError(errno, "SuctionSamplerPump::setSpeed()", errorBuf);
    fprintf(stderr, "%s\n", errorBuf);
  }
}


void BitSpeedControl::setRotationSense(DrillSledDm::RotationSense direction)
{
  DM_Time t;
  gettimeofday(&t, NULL);
  Errno errno;
  char errorBuf[errorMsgSize];
  Int32 value = direction;
  
  if ((errno = _dmObjects->bitRotationSense->write(value, &t)) != SUCCESS)
  {
    sprintDmError(errno, "BitSpeedControl::setRotationSense()", errorBuf);
    fprintf(stderr, "%s\n", errorBuf);
  }
}


void BitSpeedControl::speedCallback(Widget w,
				    XtPointer clientData,
				    XtPointer callData)
{
  BitSpeedControl *obj = (BitSpeedControl *)clientData;
  
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;

  if (cbs->reason == XmCR_DRAG)
    obj->_draggingSpeed = True;
  else
    obj->_draggingSpeed = False;

  obj->setSpeed(cbs->value);
}



void BitSpeedControl::directionCallback(Widget w,
					XtPointer clientData,
					XtPointer callData)
{
  Boolean debug = True;
  dprintf(stderr, "BitSpeedControl::directionCallback()\n");

  BitSpeedControl *obj = (BitSpeedControl *)clientData;

  DrillSledDm::RotationSense direction;
  if (w == obj->_stop)
    direction = DrillSledDm::Stop;
  else if (w == obj->_fwd)
    direction = DrillSledDm::Clockwise;
  else if (w == obj->_rev)
    direction = DrillSledDm::CounterClockwise;
  else
  {
    fprintf(stderr, 
	    "BitSpeedControl::directionCallback() - unknown direction!\n");
    return;
  }
    
  obj->setRotationSense(direction);
}




