
static char PowerSwitchGui_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/PowerSwitchGui.cc,v 1.8 1998/03/12 16:12:05 oreilly Exp $";

/*
$Log: PowerSwitchGui.cc,v $
Revision 1.8  1998/03/12 16:12:05  oreilly
Added callback method for "enable" of MotorSwitchGui

Revision 1.7  1998/02/23 16:14:03  oreilly
*** empty log message ***

Revision 1.6  1997/08/12 14:56:16  oreilly
*** empty log message ***

Revision 1.5  97/05/07  17:34:56  17:34:56  oreilly (Thomas C. O'Reilly)
Delete contained DmInputDetector in destructor.

Revision 1.4  97/04/09  14:02:09  14:02:09  oreilly (Thomas C. O'Reilly)
Added methods to get switch status, turn switch on and off

Revision 1.3  97/03/25  15:45:00  15:45:00  oreilly (Thomas C. O'Reilly)
Added callback methods, method to get status

Revision 1.2  97/03/20  12:30:41  12:30:41  oreilly (Thomas C. O'Reilly)
..

Revision 1.1  96/10/28  09:12:38  09:12:38  oreilly (Thomas C. O'Reilly)
Initial revision

*/
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Vk/VkApp.h>
#include "PowerSwitchGui.h"
#include "powerDM.h"
#include "DmErrno.h"
#include "thrusterDM.h"
#include "TiburonApp.h"

#define dprintf if (debug) fprintf

XtResource PowerSwitchGui::_resources[] = 
{
  {  
    "noPwrForeground",
    "NoPwrForeground",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(PowerSwitchGui *, _noPwrForeground),
    XmRString,
    "white"
  },

  {  
    "noPwrBackground",
    "NoPwrBackground",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(PowerSwitchGui *, _noPwrBackground),
    XmRString,
    "black"
  }
};

const char *const PowerSwitchGui::statusChangeCallback = "statusCallback";

PowerSwitchGui::PowerSwitchGui(const char *name, Widget parent, 
			       const char *switchDmPrefix, 
			       const char *switchName, 
			       int buttonWidth, int buttonHeight,
			       int period, Boolean showCurrent) :
  DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);
  installDestroyHandler();

  getResources(_resources, XtNumber(_resources));

  _statusDetector = NULL;
  
  _showCurrent = showCurrent;
  
  char prefix[MaxDmNameLen];
  
  if (!switchDmPrefix)
    _dummySwitch = True;
  else
  {
    strcpy(prefix, switchDmPrefix);
    
    if (prefix[strlen(prefix)-1] != '.')
      strcat(prefix, ".");
    
    _dummySwitch = False;
  }
  
  _button = new DynamicButton("button", _baseWidget, 
			      buttonWidth, buttonHeight);

  _switchName = strdup(switchName);

  XtVaSetValues(_button->baseWidget(),
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		NULL);

  _button->show();
  
  if (_dummySwitch)
  {
    _button->setText(switchName);
    return;
  }
  
  _button->setActivateCallback(&PowerSwitchGui::callback, (XtPointer )this);
  
  char itemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(itemName, prefix);
  strcat(itemName, SWITCH_REQUEST);
  _dmRequest = new DmEnumObject(itemName);
  if (_dmRequest->error())
  {
    _dmRequest->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_dmRequest, DmProvideFlag) == -1)
    return;

  strcpy(itemName, prefix);
  strcat(itemName, SWITCH_STATUS);
  _dmStatus = new DmEnumObject(itemName);
  if (_dmStatus->error())
  {
    _dmStatus->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  _statusDetector = 
    new DmInputDetector("status", parent, _dmStatus, this);
  
  if (showCurrent)
  {
    strcpy(itemName, prefix);
    strcat(itemName, SWITCH_CURRENT);
  
    _dmCurrent = new DmInt16Object(itemName);
    if (_dmCurrent->error())
    {
      _dmCurrent->errorMsg(errorBuf);
      setError(errorBuf);
      return;
    }
    if (addDmObject(_dmCurrent, DmConsumeFlag) == -1)
      return;
  }
  else
    _dmCurrent = NULL;


  if (setConsumePeriod(period) == -1)
    return;

  _status = SWITCH_NO_POWER;
  _current = NoCurrent;
  
  // Get colors from application
  TiburonApp *app = (TiburonApp *)theApplication;

  app->powerOnColors(&_onForeground, &_onBackground);

  // Use default foreground/background for "off" state 
  XtVaGetValues(_baseWidget, 
		XmNforeground, &_offForeground,
		XmNbackground, &_offBackground,
		NULL);
  
  app->faultColors(&_faultForeground, &_faultBackground);
  
  updateGui();
  updateFromPeer(this, NULL);
}


PowerSwitchGui::~PowerSwitchGui()
{
  free(_switchName);
  if (_statusDetector)
    delete _statusDetector;
}


void PowerSwitchGui::updateFromPeer(DmGuiObject *peer, void *clientData)
{
  char errorBuf[errorMsgSize];
  
  if (_dummySwitch)
    return;
  
  Boolean debug = False;
  dprintf(stderr, "PowerSwitchGui::updateFromPeer()\n");

  DM_Time t;
  Errno err;
  
  // Read status
  if ((err = _dmStatus->read(&_status, &t)) != SUCCESS)
  {
    sprintDmError(err, "PowerSwitchGui::updateFromPeer()", errorBuf);
    setError(errorBuf);
    return;
  }

  callCallbacks(statusChangeCallback, (void *)_status);
  
  // Set button colors appropriate to switch status
  Pixel foreground, background;
  Pixel topColor, bottomColor, selectColor, borderColor;
  Pixel feedColor;
  
  char buf[100];

  switch (_status)
  {  
    case SWITCH_NO_POWER:
    foreground = _noPwrForeground;
    background = _noPwrBackground;
    _current = NoCurrent;
    
    sprintf(buf, "%s\nNO PWR", _switchName);
    _button->setText(buf);
    feedColor = _offBackground;
    break;
    
    case SWITCH_OFF:
    foreground = _offForeground;
    background = _offBackground;
    _current = NoCurrent;
    
    sprintf(buf, "%s\nOFF", _switchName);
    _button->setText(buf);
    feedColor = _offBackground;
    break;
    
    case SWITCH_ON:
    foreground = _onForeground;
    background = _onBackground;
    feedColor = _onBackground;

    if (_showCurrent)
      // Update current display
      updateGui();
    else
    {
      sprintf(buf, "%s\nON", _switchName);
      _button->setText(buf);
    }
    break;
    
    case SWITCH_POWER_ERROR:
    foreground = _faultForeground;
    background = _faultBackground;
    feedColor = _offBackground;
    _current = NoCurrent;

    sprintf(buf, "%s\nFAULT", _switchName);
    _button->setText(buf);
    break;

    default:
    return;
  }

  Colormap colormap;
  XtVaGetValues(_baseWidget, XmNcolormap, &colormap, NULL);
  
  XmGetColors(XtScreen(_baseWidget), colormap, background, &borderColor, 
	      &topColor, &bottomColor, &selectColor);
  
  _button->setColors(foreground, background);

}



void PowerSwitchGui::updateGui(DM_Item handle)
{
  if (_dummySwitch)
    return;
  
  DM_Time t;
  char errorBuf[errorMsgSize];
  Int16 current;
  char buf[100];
  Errno err;
  
  if (_dmCurrent && _status == SWITCH_ON)
  {
    // Read current
    if ((err = _dmCurrent->read(&current, &t)) != SUCCESS)
    {
      sprintDmError(err, "PowerSwitchGui::updateGui()", errorBuf);
      setError(errorBuf);
      sprintf(buf, "curr read err");
      _button->setText(buf);
      return;
    }

    if (current != _current)
    {
      sprintf(buf, "%s\n%4.1fA", _switchName, current / 1000.);
      _button->setText(buf);
      _current = current;
    }
  }
  else
    _current = NoCurrent;
}


switchStatus PowerSwitchGui::status()
{
  return (switchStatus )_status;
}


void PowerSwitchGui::callback(Widget w, 
			      XtPointer clientData, XtPointer callData)
{
  PowerSwitchGui *obj = (PowerSwitchGui *)clientData;
  obj->toggleState();
}


void PowerSwitchGui::toggleState()
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  Int32 status, newStatus;

  Errno err;
  
  // Read present status
  if ((err = _dmStatus->read(&status, &t)) != SUCCESS)
  {
    sprintDmError(err, "PowerSwitchGui::toggleState()", errorBuf);
    setError(errorBuf);
    return;
  }
  
  switch (status)
  {
    case SWITCH_OFF:
    newStatus = SWITCH_ON;
    break;
    
    default:
    newStatus = SWITCH_OFF;
  }

  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if ((err = _dmRequest->write(newStatus, &t)) != SUCCESS)
  {
    sprintDmError(err, "PowerSwitchGui::toggleState()", errorBuf);
    setError(errorBuf);
    return;
  }
  
}  


int PowerSwitchGui::turnOn()
{
  return requestState(SWITCH_ON);
}


int PowerSwitchGui::turnOff()
{
  return requestState(SWITCH_OFF);
}


int PowerSwitchGui::requestState(switchStatus state)
{
  DM_Time t;
  
  t.tv_sec = time(NULL);
  t.tv_usec = 0;

  Errno errno;
  char errorBuf[errorMsgSize];
  
  if ((errno = _dmRequest->write(state, &t)) != SUCCESS)
  {
    sprintDmError(errno, "PowerSwitchGui::toggleState()", errorBuf);
    setError(errorBuf);
    return -1;
  }

  return 0;
}


void PowerSwitchGui::setSensitive(Boolean sensitive)
{
  _button->setSensitive(sensitive);
}


const char *const MotorSwitchGui::enableStatusChangeCallback = 
"enableStatusCallback";

MotorSwitchGui::MotorSwitchGui(const char *name, Widget parent, 
			       const char *switchDmPrefix, 
			       const char *enableDmPrefix, 
			       const char *switchName, 
			       int buttonWidth, int buttonHeight,
			       int period) :
  PowerSwitchGui(name, parent, switchDmPrefix, switchName, 
		 buttonWidth, buttonHeight, period, True)
{
  _enableButton = 
    XtVaCreateManagedWidget("enable", xmPushButtonWidgetClass, 
			    _baseWidget, 
			    XmNheight, buttonHeight,
			    XmNrecomputeSize, False,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, _button->baseWidget(),
			    NULL);
  
  XtAddCallback(_enableButton, XmNactivateCallback, 
		&MotorSwitchGui::enableCallback, (XtPointer )this);


  char itemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  if (enableDmPrefix[strlen(enableDmPrefix)-1] != '.')
    strcat((char *)enableDmPrefix, ".");
  
  strcpy(itemName, enableDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");
  
  strcat(itemName, MOTOR_ENABLE_REQ_DM);
  _dmEnableRequest = new DmEnumObject(itemName);
  if (_dmEnableRequest->error())
  {
    _dmEnableRequest->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_dmEnableRequest, DmProvideFlag) == -1)
    return;

  strcpy(itemName, enableDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");

  strcat(itemName, MOTOR_ENABLE_STATUS_DM);
  _dmEnableStatus = new DmEnumObject(itemName);
  if (_dmEnableStatus->error())
  {
    _dmEnableStatus->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  new DmInputDetector("enable", parent, _dmEnableStatus, this);

  updateFromPeer(this, NULL);
}



MotorSwitchGui::~MotorSwitchGui()
{
}


void MotorSwitchGui::updateFromPeer(DmGuiObject *peer, void *clientData)
{
  Boolean debug = False;
  dprintf(stderr, "MotorSwitchGui::updateFromPeer()\n");
  
  PowerSwitchGui::updateFromPeer(peer, clientData);

  if (_status == SWITCH_ON)
    XtSetSensitive(_enableButton, True);
  else
    XtSetSensitive(_enableButton, False);


  // Read enabled state
  Errno err;
  char errorBuf[errorMsgSize];
  DM_Time t;
  
  if ((err = _dmEnableStatus->read(&_enableStatus, &t)) != SUCCESS)
  {
    sprintDmError(err, "MotorSwitchGui::updateFromPeer()", errorBuf);
    setError(errorBuf);
    return;
  }      

  Pixel foreground, background;
  char *msg;
  
  switch (_enableStatus)
  {
    case DISABLE_MOTOR:
    XtVaGetValues(_baseWidget, 
		  XmNforeground, &foreground,
		  XmNbackground, &background,
		  NULL);

    msg = "Enable";
    break;
    
    case ENABLE_MOTOR:
    foreground = _onForeground;
    background = _onBackground;
    msg = "Enable\nOK";
    break;
    
    case MOOG_MOTOR_FAULT:
    foreground = _faultForeground;
    background = _faultBackground;
    msg = "Enable\nFault";
    break;
  }

  callCallbacks(enableStatusChangeCallback, (void *)_enableStatus);

  // If main switch has no power, then set enable button color accordingly
  if (_status == SWITCH_NO_POWER)
  {
    foreground = _noPwrForeground;
    background = _noPwrBackground;
  }
  
  Colormap colormap;
  XtVaGetValues(_baseWidget, XmNcolormap, &colormap, NULL);

  Pixel borderColor, topColor, bottomColor, selectColor;
  
  XmGetColors(XtScreen(_baseWidget), colormap, background, &borderColor, 
	      &topColor, &bottomColor, &selectColor);
  
  XmString xmstr = XmStringCreateLtoR(msg, XmSTRING_DEFAULT_CHARSET);
  
  XtVaSetValues(_enableButton,
		XmNforeground, foreground,
		XmNbackground, background,
		XmNtopShadowColor, topColor,
		XmNbottomShadowColor, bottomColor,
		XmNborderColor, borderColor, 
		XmNarmColor, selectColor, 
		XmNlabelString, xmstr,
		NULL);

  XmStringFree(xmstr);
}



void MotorSwitchGui::toggleEnableState()
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  motorEnableState newStatus;
  Errno err;
  
  // Read present status
  if ((err = _dmEnableStatus->read(&_enableStatus, &t)) != SUCCESS)
  {
    sprintDmError(err, "MotorSwitchGui::toggleEnableState()", errorBuf);
    setError(errorBuf);
    return;
  }

  switch (_enableStatus)
  {
    case DISABLE_MOTOR:
    newStatus = ENABLE_MOTOR;
    break;
    
    default:
    newStatus = DISABLE_MOTOR;
  }
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if ((err = _dmEnableRequest->write(newStatus, &t)) != SUCCESS)
  {
    sprintDmError(err, "MotorSwitchGui::toggleEnableState()", errorBuf);
    setError(errorBuf);
    return;
  }
}

void MotorSwitchGui::enableCallback(Widget w, 
				    XtPointer clientData, XtPointer callData)  
{
  MotorSwitchGui *obj = (MotorSwitchGui *)clientData;
  obj->toggleEnableState();
}


motorEnableState MotorSwitchGui::enableStatus()
{
  return (motorEnableState )_enableStatus;
}
