#include <Xm/RowColumn.h>
#include "LightSwitch.h"
#include "TiburonApp.h"

LightSwitch::LightSwitch(const char *name, Widget parent,
			 const char *lpDconDmPrefix,
			 const char *hpDconDmPrefix,
			 const char *ballastDmPrefix,
			 const char *lightDmPrefix,
			 const char *switchName,
			 int buttonWidth, int buttonHeight,
			 int period)

  : DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
				 XmNorientation, XmVERTICAL,
				 NULL);
  installDestroyHandler();
  _switchName = strdup(switchName);
  
  _powerButton = new DynamicButton("powerButton", _baseWidget, 
			     buttonWidth, buttonHeight);

  _powerButton->setActivateCallback(&LightSwitch::powerButtonCallback, 
				    (XtPointer )this);

  _powerButton->show();
  
  char itemName[MaxDmNameLen];
  
  strcpy(itemName, lpDconDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");
  
  char *namePtr = itemName + strlen(itemName);

  strcpy(namePtr, SWITCH_REQUEST);
  _dmLpDconReq = new DmEnumObject(itemName);
  if (addDmObject(_dmLpDconReq, DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, SWITCH_STATUS);
  _dmLpDconStatus = new DmEnumObject(itemName);
  if (addDmObject(_dmLpDconStatus, DmConsumeFlag) == -1)
    return;

  strcpy(itemName, hpDconDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");
  
  namePtr = itemName + strlen(itemName);

  strcpy(namePtr, SWITCH_REQUEST);
  _dmHpDconReq = new DmEnumObject(itemName);
  if (addDmObject(_dmHpDconReq, DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, SWITCH_STATUS);
  _dmHpDconStatus = new DmEnumObject(itemName);
  if (addDmObject(_dmHpDconStatus, DmConsumeFlag) == -1)
    return;

  strcpy(itemName, ballastDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");
  
  namePtr = itemName + strlen(itemName);

  strcpy(namePtr, SWITCH_REQUEST);
  _dmBallastReq = new DmEnumObject(itemName);
  if (addDmObject(_dmBallastReq, DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, SWITCH_STATUS);
  _dmBallastStatus = new DmEnumObject(itemName);
  if (addDmObject(_dmBallastStatus, DmConsumeFlag) == -1)
    return;

  strcpy(itemName, lightDmPrefix);
  if (itemName[strlen(itemName)-1] != '.')
    strcat(itemName, ".");
  
  namePtr = itemName + strlen(itemName);

  strcpy(namePtr, SWITCH_REQUEST);
  _dmLightReq = new DmEnumObject(itemName);
  if (addDmObject(_dmLightReq, DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, SWITCH_STATUS);
  _dmLightStatus = new DmEnumObject(itemName);
  if (addDmObject(_dmLightStatus, DmConsumeFlag) == -1)
    return;
  
  setConsumePeriod(period);
  
  _state = _prevState = Off;
  setState(Off);
  _buttonState = Off;
  
  _error = False;
  updateGui();
}


LightSwitch::~LightSwitch()
{
  if (_switchName)
    free(_switchName);
}


void LightSwitch::updateGui(DM_Item handle)
{
  char errorBuf[errorMsgSize];
  Errno errno;
  DM_Time t;
  Int32 status;
  
  /* Read status items */
  if ((errno = _dmLpDconStatus->read(&status, &t)) != SUCCESS)
  {
  }
  _lpDconStatus = status;

  if ((errno = _dmHpDconStatus->read(&status, &t)) != SUCCESS)
  {
  }
  _hpDconStatus = status;

  if ((errno = _dmBallastStatus->read(&status, &t)) != SUCCESS)
  {
  }
  _ballastStatus = status;
  
  if ((errno = _dmLightStatus->read(&status, &t)) != SUCCESS)
  {
  }
  _lightStatus = status;

  switch (_state)
  {
    case SwitchingOn:
    switchOn();
    break;
    
    case SwitchingOff:
    switchOff();
    break;
  }
  
  TiburonApp *app = (TiburonApp *)theApplication;
  Pixel foreground, background;
  Boolean changeColor = False;
  
  if (_lpDconStatus == SWITCH_ON && _hpDconStatus == SWITCH_ON &&
      _ballastStatus == SWITCH_ON && _lightStatus == SWITCH_ON)
  {
    if (_state != SwitchingOff)
      setState(On);

    if (_buttonState == Off)
    {
      changeColor = True;
      app->powerOnColors(&foreground, &background);
      _buttonState = On;
    }
    _error = False;
  }
  else if (_lpDconStatus == SWITCH_POWER_ERROR ||
	   _hpDconStatus == SWITCH_POWER_ERROR ||
	   _ballastStatus == SWITCH_POWER_ERROR ||
	   _lightStatus == SWITCH_POWER_ERROR)
  {
    if (!_error)
    {
      changeColor = True;
      app->faultColors(&foreground, &background);
    }
    _error = True;
  }
  else
  {
    if (_lightStatus == SWITCH_OFF && _state != SwitchingOn)
      setState(Off);
    
    if (_buttonState == On)
    {
      changeColor = True;
      XtVaGetValues(_baseWidget, 
		    XmNforeground, &foreground,
		    XmNbackground, &background,
		    NULL);

      _buttonState = Off;
    }
    _error = False;
  }

  if (changeColor)
    _powerButton->setColors(foreground, background);
}



void LightSwitch::switchOn()
{
  char errorBuf[errorMsgSize];
  Errno errno;
  DM_Time t;
  
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if (_lpDconStatus != SWITCH_ON)
  {
    errno = _dmLpDconReq->write(SWITCH_ON, &t);
  }
  else if (_hpDconStatus != SWITCH_ON)
  {
    errno = _dmHpDconReq->write(SWITCH_ON, &t);
  }
  else if (_ballastStatus != SWITCH_ON)
  {
    errno = _dmBallastReq->write(SWITCH_ON, &t);
  }
  else if (_lightStatus != SWITCH_ON)
  {
    errno = _dmLightReq->write(SWITCH_ON, &t);
  }
}


void LightSwitch::switchOff()
{
  char errorBuf[errorMsgSize];
  Errno errno;
  DM_Time t;
  
  t.tv_sec = time(NULL);
  t.tv_usec = 0;

  if (_lightStatus != SWITCH_OFF)
  {
    if ((errno = _dmLightReq->write(SWITCH_OFF, &t)) != SUCCESS)
    {
    }
  }
}


void LightSwitch::toggleState()
{
  if (_state == On || _state == SwitchingOn)
  {
    setState(SwitchingOff);
    switchOff();
  }
  else if (_state == Off || _state == SwitchingOff)
  {
    setState(SwitchingOn);
    switchOn();
  }
}

void LightSwitch::setState(State state)
{
  _prevState = _state;
  _state = state;

  char buf[100];
  
  switch (state)
  {
    case Off:
    sprintf(buf, "%s\nOFF", _switchName);
    _powerButton->setText(buf);
    break;
    
    case On:
    sprintf(buf, "%s\nON", _switchName);
    _powerButton->setText(buf);
    break;
    
    case SwitchingOff:
    sprintf(buf, "%s\nSwitching OFF", _switchName);
    _powerButton->setText(buf);
    break;
    
    case SwitchingOn:
    sprintf(buf, "%s\nSwitching ON", _switchName);
    _powerButton->setText(buf);
    break;
  }
}    


void LightSwitch::powerButtonCallback(Widget w, 
				       XtPointer clientData, 
				       XtPointer callData)
{
  LightSwitch *obj = (LightSwitch *)clientData;
  obj->toggleState();
}

