#include <values.h>
#include <Xm/RowColumn.h>
#include <Xm/ToggleB.h>
#include <Xm/Label.h>
#include <Vk/VkErrorDialog.h>
#include "CommRelays.h"
#include "TiburonApp.h"
#include "telemDiag.h"
#include "DmErrno.h"

#define dprintf if (debug) fprintf

CommRelays::CommRelays(const char *name, Widget parent, const char *dmPrefix)
  : DmGuiObject(name, parent)
{
  _gfCurrent = 0;
  _stripChart = 0;
  
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
				 XmNorientation, XmVERTICAL,
				 NULL);
  installDestroyHandler();
  
  Widget mgr;
  
  mgr = XtVaCreateWidget("mgr", xmRowColumnWidgetClass, _baseWidget, 
			 XmNorientation, XmHORIZONTAL, NULL);
  
  char widgetName[100];
  sprintf(widgetName, "%sLabel", name);
  
  Widget label = 
    XtVaCreateManagedWidget(widgetName, xmLabelWidgetClass, mgr, NULL);
  
  char itemName[MaxDmNameLen];
  strcpy(itemName, dmPrefix);
  char *namePtr = itemName + strlen(itemName);
  
  strcpy(namePtr, LOCAL_GND_FLT_CURRENT_DM);
  DmInt16Object *dmObject = new DmInt16Object(itemName);

  SystemAlarms *alarms = ((TiburonApp *)theApplication)->systemAlarms;
  
  char errorBuf[errorMsgSize];

  strcpy(namePtr, LOCAL_GND_FLT_ALARM_DM);

  Alarm *alarm;
  if ((alarm = alarms->find(itemName)) == NULL)
  {
    sprintf(errorBuf,
	    "CommRelays::CommRelays() - couldn't find alarm \"%s\"",
	    itemName);

    theErrorDialog->postAndWait(errorBuf);
  }
  
  
  _gfCurrent = new AlarmedInt16Text("gfCurrent", mgr, "%.3f",
				    dmObject, 500, alarm, True);
  
  _gfCurrent->show();

  XtManageChild(mgr);

  _stripChart = new DmStripChart("stripChart", _baseWidget,
				 dmObject->getName(), 5);
  _stripChart->show();
  
  
  mgr =
    XtVaCreateWidget("mgr", xmRowColumnWidgetClass, _baseWidget,
		     XmNpacking, XmPACK_COLUMN,
		     XmNnumColumns, 3,
		     XmNorientation, XmVERTICAL,
		     NULL);
  
  
  for (int i = 0; i < NCommRelaySwitches; i++)
  {
    sprintf(widgetName, "switch%02d", i);
    
    _relay[i] = 
      XtVaCreateManagedWidget(widgetName, xmToggleButtonWidgetClass, mgr,
			      NULL);

    XtAddCallback(_relay[i], XmNvalueChangedCallback,
		  &CommRelays::relayCallback,
		  (XtPointer )this);

  }

  XtManageChild(mgr);

  strcpy(namePtr, TELEM_RELAY_CONTROL_DM);
  _dmRelayMask = new DmNat32Object(itemName);
  
  if (addDmObject(_dmRelayMask, DmConsumeFlag | DmProvideFlag) == -1)
    return;

  int period;
  period = AperiodicGuaranteed;

//  period = 200;  // TEST TEST TEST 
  
  if (setConsumePeriod(period) == -1)
    return;
  
  _prevMask = MAXLONG;
  
  updateGui();
}


CommRelays::~CommRelays()
{
  delete _gfCurrent;
  delete _stripChart;
}


void CommRelays::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  char errorBuf[errorMsgSize];
  Boolean debug = False;
  
  Nat32 mask;
  if ((errno = _dmRelayMask->read(&mask, &t)) != SUCCESS)
  {
    sprintDmError(errno, "CommRelays::updateGui()", errorBuf);
    setError(errorBuf);
    dprintf(stderr, "%s\n", errorBuf);
    return;
  }

  dprintf(stderr, "mask=%d\n", mask);

  if (mask == _prevMask)
    return;
  
  _prevMask = mask;
  
  for (int bit = 0; bit < NCommRelaySwitches; bit++)
  {
    if (mask & (01 << bit))
      XtVaSetValues(_relay[bit], XmNset, True, NULL);
    else
      XtVaSetValues(_relay[bit], XmNset, False, NULL);
  }
}


void CommRelays::write()
{
  Nat32 mask = 0;

  Boolean set;
  
  for (int bit = 0; bit < NCommRelaySwitches; bit++)
  {
    XtVaGetValues(_relay[bit], XmNset, &set, NULL);
    if (set)
    {
      mask = mask | (01 << bit); 
    }
  }

  DM_Time t;
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  Errno errno;
  char errorBuf[errorMsgSize];
  if ((errno = _dmRelayMask->write(mask, &t)) != SUCCESS)
  {
    sprintDmError(errno, "CommRelays::write()", errorBuf);
    setError(errorBuf);
    theErrorDialog->postAndWait(errorBuf);
  }
}


void CommRelays::relayCallback(Widget w,
			       XtPointer clientData,
			       XtPointer callData)
{
  CommRelays *obj = (CommRelays *)clientData;

  obj->write();
}

