#include <stdlib.h>
#include <values.h>
#include <Xm/Form.h>
#include "DmText.h"
#include "DmErrno.h"
#include "parseUtils.h"


DmText::DmText(const char *name, Widget parent)
  : DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);
  installDestroyHandler();

  text = new TextField("text", _baseWidget);
  XtVaSetValues(text->baseWidget(),
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		NULL);
  
  text->show();
  text->addCallback(TextField::acceptCallback, this,
		    (VkCallbackMethod )&DmText::writeValue);
}


DmText::~DmText()
{
}


void DmText::okayCallback(VkCallbackObject *obj,
			  void *clientData,
			  void *callData)
{
}


DmStringText::DmStringText(const char *name, Widget parent, 
			   const char *dmItemName, unsigned length, int period)

  : DmText(name, parent)
{
  if ((_valueBuf = (char *)malloc(length + 1)) == NULL)
  {
    setError("malloc() of _valueBuf failed");
    return;
  }
  
  _dmObject = new DmStringObject(dmItemName, length);

  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_dmObject, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(period) == -1)
    return;

  updateGui();
}


DmStringText::~DmStringText()
{
  if (_valueBuf)
    free(_valueBuf);
}


void DmStringText::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  
  if ((errno = _dmObject->read(_valueBuf, &t)) != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    
    sprintDmError(errno,
		  "DmStringText::updateGui() - ", errorBuf);

    setError(errorBuf);
    return;
  }

  text->set(_valueBuf);
}


Boolean DmStringText::validInput(char *errorMsg)
{
  return True;
}


Errno DmStringText::writeValue()
{
  Errno err;
  if ((err = _dmObject->startProvide(DM_ASYNC)) != SUCCESS)
    return err;
  
  const char *txt = text->get();
  DM_Time t;
  t.tv_sec = time(NULL);

  err = _dmObject->write((char *)txt, &t);

  _dmObject->stopProvide();
  return err;
}



DmInt16Text::DmInt16Text(const char *name, Widget parent, 
			 const char *dmItemName, int period)
  : DmText(name, parent)
{
  _dmObject = new DmInt16Object(dmItemName);
  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  if (addDmObject(_dmObject, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(period) == -1)
    return;

  _prevValue = MAXSHORT;
  
  updateGui();
}


DmInt16Text::~DmInt16Text()
{
}


void DmInt16Text::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  Int16 value;
  
  if ((errno = _dmObject->read(&value, &t)) != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    
    sprintDmError(errno,
		  "DmInt16Text::updateGui() - ", errorBuf);

    setError(errorBuf);
    return;
  }

  char buf[100];
  
  if (value != _prevValue)
  {
    sprintf(buf, "%d", value);
    text->set(buf);
  }
  
  _prevValue = value;
}


Errno DmInt16Text::writeValue()
{
  Errno err;
  if ((err = _dmObject->startProvide(DM_ASYNC)) != SUCCESS)
    return err;
  
  const char *txt = text->get();
  Int16 value = atoi(txt);
  
  DM_Time t;
  t.tv_sec = time(NULL);

  err = _dmObject->write(value, &t);

  _dmObject->stopProvide();
  return err;
}


Boolean DmInt16Text::validInput(char *errorMsg)
{
  const char *txt = text->get();
  if (!isInteger((char *)txt))
  {
    sprintf(errorMsg, "\"%s\" - invalid integer", txt);
    return False;
  }
  else
    return True;
}


DmNat16Text::DmNat16Text(const char *name, Widget parent, 
			 const char *dmItemName, int period)
  : DmText(name, parent)
{
  _dmObject = new DmNat16Object(dmItemName);
  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  if (addDmObject(_dmObject, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(period) == -1)
    return;

  _prevValue = MAXSHORT;
  
  updateGui();
}


DmNat16Text::~DmNat16Text()
{
}


void DmNat16Text::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  Nat16 value;
  
  if ((errno = _dmObject->read(&value, &t)) != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    
    sprintDmError(errno,
		  "DmNat16Text::updateGui() - ", errorBuf);

    setError(errorBuf);
    return;
  }

  char buf[100];
  
  if (value != _prevValue)
  {
    sprintf(buf, "%d", value);
    text->set(buf);
  }
  
  _prevValue = value;
}


Errno DmNat16Text::writeValue()
{
  Errno err;
  if ((err = _dmObject->startProvide(DM_ASYNC)) != SUCCESS)
    return err;
  
  const char *txt = text->get();
  Nat16 value = atoi(txt);
  
  DM_Time t;
  t.tv_sec = time(NULL);

  err = _dmObject->write(value, &t);

  _dmObject->stopProvide();
  return err;
}


Boolean DmNat16Text::validInput(char *errorMsg)
{
  const char *txt = text->get();
  if (!isInteger((char *)txt))
  {
    sprintf(errorMsg, "\"%s\" - invalid integer", txt);
    return False;
  }
  else
  {
    int value = atoi(txt);

    if (value >= 0 && value <= MAXSHORT)
      return True;
    else return False;
  }
  
}



DmFlt32Text::DmFlt32Text(const char *name, Widget parent, 
			 const char *dmItemName, int period)
  : DmText(name, parent)
{
  _dmObject = new DmFlt32Object(dmItemName);
  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  if (addDmObject(_dmObject, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(period) == -1)
    return;

  _prevValue = MAXFLOAT;
  
  updateGui();
}


DmFlt32Text::~DmFlt32Text()
{
}


void DmFlt32Text::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  Flt32 value;
  
  if ((errno = _dmObject->read(&value, &t)) != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    
    sprintDmError(errno,
		  "DmFlt32Text::updateGui() - ", errorBuf);

    setError(errorBuf);
    return;
  }

  char buf[100];
  
  if (value != _prevValue)
  {
    sprintf(buf, "%.1f", value);
    text->set(buf);
  }
  
  _prevValue = value;
}


Errno DmFlt32Text::writeValue()
{
  Errno err;
  if ((err = _dmObject->startProvide(DM_ASYNC)) != SUCCESS)
    return err;
  
  const char *txt = text->get();
  Flt32 value = atof(txt);
  
  DM_Time t;
  t.tv_sec = time(NULL);

  err = _dmObject->write(value, &t);

  _dmObject->stopProvide();
  return err;
}


Boolean DmFlt32Text::validInput(char *errorMsg)
{
  const char *txt = text->get();
  if (!isFloat((char *)txt))
  {
    sprintf(errorMsg, "\"%s\" - invalid floating point number", txt);
    return False;
  }
  else
    return True;
}



DmFlt64Text::DmFlt64Text(const char *name, Widget parent, 
			 const char *dmItemName, int period)
  : DmText(name, parent)
{
  _dmObject = new DmFlt64Object(dmItemName);
  if (_dmObject->error())
  {
    char errorBuf[errorMsgSize];
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  if (addDmObject(_dmObject, DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(period) == -1)
    return;

  _prevValue = MAXDOUBLE;
  
  updateGui();
}


DmFlt64Text::~DmFlt64Text()
{
}


void DmFlt64Text::updateGui(DM_Item handle)
{
  DM_Time t;
  Errno errno;
  Flt64 value;
  
  if ((errno = _dmObject->read(&value, &t)) != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    
    sprintDmError(errno,
		  "DmFlt64Text::updateGui() - ", errorBuf);

    setError(errorBuf);
    return;
  }

  char buf[100];
  
  if (value != _prevValue)
  {
    sprintf(buf, "%.1f", value);
    text->set(buf);
  }
  
  _prevValue = value;
}


Errno DmFlt64Text::writeValue()
{
  Errno err;
  if ((err = _dmObject->startProvide(DM_ASYNC)) != SUCCESS)
    return err;
  
  const char *txt = text->get();
  Flt64 value = atof(txt);
  
  DM_Time t;
  t.tv_sec = time(NULL);

  err = _dmObject->write(value, &t);

  _dmObject->stopProvide();
  return err;
}


Boolean DmFlt64Text::validInput(char *errorMsg)
{
  const char *txt = text->get();
  if (!isFloat((char *)txt))
  {
    sprintf(errorMsg, "\"%s\" - invalid floating point number", txt);    
    return False;
  }
  else
    return True;
}

