#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include "VideoSwitcher.h"
#include "DmErrno.h"
#include "vmeIbc.h"

VideoSwitch::VideoSwitch(const char *name, Widget parent, 
			 const char *src1Name, const char *src2Name,
			 VideoSwitcher *switcher)
  : VkComponent(name)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);
  installDestroyHandler();

  sources = new VkRadioBox("sources", _baseWidget);

  _source1 = sources->addItem((char *)src1Name, False, 
			      &VideoSwitch::toggleCallback, this);

  _source2 = sources->addItem((char *)src2Name, False, 
			      &VideoSwitch::toggleCallback, this);
  
  XtVaSetValues(sources->baseWidget(),
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNorientation, XmVERTICAL,
		XmNradioAlwaysOne, False,
		NULL);
  
  sources->show();

  _switcher = switcher;
}



VideoSwitch::~VideoSwitch()
{
}


void VideoSwitch::toggleCallback(Widget w,
				 void *clientData, void *callData)
{
  XmToggleButtonCallbackStruct *cb = 
    (XmToggleButtonCallbackStruct *)callData;
  
  if (!cb->event) {
    // Widget was programmatically toggled (i.e., not by mouse click),
    // so just forget about it.
    return;
  }

  VideoSwitch *obj = (VideoSwitch *)clientData;
  int index = -1;
  if (w == obj->_source1)
    index = 0;
  else if (w == obj->_source2)
    index = 1;
    
  obj->_switcher->switchToggled(obj, index);
}


VideoSwitcher::VideoSwitcher(const char *name, Widget parent)
  : DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, 
				 XmNorientation, XmHORIZONTAL,
				 NULL);
  installDestroyHandler();
  
  Widget column1 = 
    XtVaCreateWidget("column1", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmVERTICAL,
		     XmNleftAttachment, XmATTACH_FORM,
		     XmNtopAttachment, XmATTACH_FORM,
		     NULL);
  

  Widget column2 = 
    XtVaCreateWidget("column2", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmVERTICAL,
		     XmNleftAttachment, XmATTACH_WIDGET,
		     XmNleftWidget, column1,
		     XmNtopAttachment, XmATTACH_FORM,
		     NULL);

  for (int i = 0; i < NVideoChannels; i++)
  {
    char switchName[100];
    char *src1Name;
    char *src2Name;
    
    sprintf(switchName, "videoSwitch%d", i + 1);
    switch (i)
    {
      case 0:
      src1Name = "stbdMainRed";
      src2Name = "stbdMainNTSC";
      break;
      
      case 1:
      src1Name = "stbdMainGreen";
      src2Name = "scienceAux";
      break;
      
      case 2:
      src1Name = "stbdMainBlue";
      src2Name = "aux1";
      break;
      
      case 3:
      src1Name = "portMainNTSC";
      src2Name = "pilotSit";
      break;
      
      case 4:
      src1Name = "aux3";
      src2Name = "toolsled1";
      break;
      
      case 5:
      src1Name = "aux2";
      src2Name = "toolsled2";
      break;
    }
    
    Widget mgr;
    if (i < 3)
      mgr = column1;
    else
      mgr = column2;
    
    _switch[i] = new VideoSwitch(switchName, mgr, src1Name, src2Name, this);
    
    _switch[i]->show();
  }

  XtManageChild(column1);
  XtManageChild(column2);

  _dmObject = new DmNat16Object(VMEIBC_DM_PREFIX VME_VIDEO_SWITCH_DM);
  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_dmObject, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  if (setConsumePeriod(Aperiodic) == -1)
    return;
  
  updateGui();
}


VideoSwitcher::~VideoSwitcher()
{
}


void VideoSwitcher::updateGui(DM_Item handle)
{
  Nat16 valueMask;
  DM_Time t;
  char errorBuf[errorMsgSize];
  Errno errno;
  
  if ((errno = _dmObject->read(&valueMask, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VideoSwitcher::updateGui()", errorBuf);
    setError(errorBuf);
    return;
  }

  int nBits = NVideoChannels * 2;
  for (int i = 0; i < nBits; i++)
  {
    int switchNo = i / 2;

    Boolean value;
    if (valueMask & (01 << i))
      value = True;
    else 
      value = False;

    if (!(i % 2)) {
      _switch[switchNo]->sources->setValue(0, value);
    }
    else {
      _switch[switchNo]->sources->setValue(1, value);
    }
  }
}


void VideoSwitcher::switchToggled(VideoSwitch *videoSwitch, int index)
{
  int i;
  int switchNo = -1;
  for (i = 0; i < NVideoChannels; i++)
  {
    if (_switch[i] == videoSwitch)
    {
      switchNo = i;
      break;
    }    
  }

  if (switchNo == -1)
  {
    setError("VideoSwitcher::switchToggled() - couldn't find switch!");
    prtErrorMsg();
    return;
  }

  if (switchNo < 3)
  {
    for (i = 0; i < 3; i++)
      _switch[i]->sources->setValue(index, True);
  }

  // Read state of switches and write to data manager
  Nat16 valueMask = 0;
  for (switchNo = 0; switchNo < NVideoChannels; switchNo++)
  {
    for (index = 0; index < 2; index++)
    {
      if (_switch[switchNo]->sources->getValue(index))
      {
	int bitNo = 2 * switchNo + index;
	valueMask |= (01 << bitNo);
      }
    }
  }

  char errorBuf[errorMsgSize];
  Errno errno;
  DM_Time t;
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if ((errno = _dmObject->write(valueMask, &t)) != SUCCESS) 
  {
    sprintDmError(errno, "VideoSwitcher::switchToggled()", errorBuf);
    setError(errorBuf);
    return;
  }
}

