static char MomentaryPowerSwitch_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/MomentaryPowerSwitch.cc,v 1.1 1998/02/23 16:14:03 oreilly Exp $";

/*
$Log: MomentaryPowerSwitch.cc,v $
Revision 1.1  1998/02/23 16:14:03  oreilly
Initial revision

*/
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Vk/VkApp.h>
#include "MomentaryPowerSwitch.h"
#include "powerDM.h"
#include "DmErrno.h"
#include "thrusterDM.h"
#include "TiburonApp.h"

#define dprintf if (debug) fprintf

XtResource MomentaryPowerSwitch::_resources[] = 
{
  {  
    "noPwrForeground",
    "NoPwrForeground",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(MomentaryPowerSwitch *, _noPwrForeground),
    XmRString,
    "white"
  },

  {  
    "noPwrBackground",
    "NoPwrBackground",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(MomentaryPowerSwitch *, _noPwrBackground),
    XmRString,
    "black"
  }
};

const char *const MomentaryPowerSwitch::statusChangeCallback 
  = "statusCallback";

MomentaryPowerSwitch::MomentaryPowerSwitch(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->setArmCallback(&MomentaryPowerSwitch::armCallback, 
			  (XtPointer )this);

  _button->setDisarmCallback(&MomentaryPowerSwitch::disarmCallback, 
			     (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);
}


MomentaryPowerSwitch::~MomentaryPowerSwitch()
{
  free(_switchName);
  if (_statusDetector)
    delete _statusDetector;
}


void MomentaryPowerSwitch::updateFromPeer(DmGuiObject *peer, void *clientData)
{
  char errorBuf[errorMsgSize];
  
  if (_dummySwitch)
    return;
  
  Boolean debug = False;
  dprintf(stderr, "MomentaryPowerSwitch::updateFromPeer()\n");

  DM_Time t;
  Errno err;
  
  // Read status
  if ((err = _dmStatus->read(&_status, &t)) != SUCCESS)
  {
    sprintDmError(err, "MomentaryPowerSwitch::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\n", _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 MomentaryPowerSwitch::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, "MomentaryPowerSwitch::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 MomentaryPowerSwitch::status()
{
  return (switchStatus )_status;
}


void MomentaryPowerSwitch::armCallback(Widget w, 
				       XtPointer clientData, 
				       XtPointer callData)
{
  MomentaryPowerSwitch *obj = (MomentaryPowerSwitch *)clientData;
  obj->requestState(SWITCH_ON);
}


void MomentaryPowerSwitch::disarmCallback(Widget w, 
					  XtPointer clientData, 
					  XtPointer callData)
{
  MomentaryPowerSwitch *obj = (MomentaryPowerSwitch *)clientData;
  obj->requestState(SWITCH_OFF);
}


int MomentaryPowerSwitch::turnOn()
{
  return requestState(SWITCH_ON);
}


int MomentaryPowerSwitch::turnOff()
{
  return requestState(SWITCH_OFF);
}


int MomentaryPowerSwitch::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, "MomentaryPowerSwitch::toggleState()", errorBuf);
    setError(errorBuf);
    return -1;
  }

  return 0;
}


void MomentaryPowerSwitch::setSensitive(Boolean sensitive)
{
  _button->setSensitive(sensitive);
}


