#include <values.h>
#include <Xm/Form.h>
#include "DmBarGraph.h"
#include "TiburonApp.h"
#include "AlarmedObject.h"



XtResource DmBarGraph::_resources[] = 
{
  {
    "nonAlarmBarColor",
    "NonAlarmBarColor",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(DmBarGraph *, _okBarColor),
    XmRString, 
    "lightgray"
  }
};


DmBarGraph::DmBarGraph(const char *name, Widget parent) 
  : DmGuiObject(name, parent)
{ 
  _parent = parent;
  _barGraph = NULL;
  _alarmDetector = NULL;
}


DmBarGraph::~DmBarGraph() 
{
  if (_alarmDetector)
    delete _alarmDetector;

  if (_barGraph)
    XtRemoveEventHandler(_barGraph,
			 ButtonPressMask,
			 False, 
			 (XtEventHandler )&DmBarGraph::eventHandler, 
			 (XtPointer )this);
}


void DmBarGraph::initialize(DmObject *dmObject, int period,
			    char *alarmName, float min, float max,
			    DM_Type dataType)
{
  _baseWidget = 
    XtCreateWidget(_name, xmFormWidgetClass, _parent, NULL, 0);
  
  installDestroyHandler();
  getResources(_resources, XtNumber(_resources));
  
  _barGraph = 
    XtVaCreateManagedWidget("barGraph", xcBarGraphWidgetClass, _baseWidget, 
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    NULL);


  XtAddEventHandler(_barGraph,
		    ButtonPressMask,
		    False, 
		    (XtEventHandler )&DmBarGraph::eventHandler, 
		    (XtPointer )this);

  XcDType xcType;
  XcVType minimum;
  XcVType maximum;

  /* Always set bar graph data type to float, because even integer
     data can have non-integer multiplier. */
  xcType = XcFval;
  minimum.fval = min;
  maximum.fval = max;
  int decimalPlaces;
  
  switch (dataType)
  {
    case DM_INT16:
    case DM_NAT16:
    case DM_INT32:
    case DM_NAT32:
    decimalPlaces = 0;
    break;
    

    case DM_FLT32:
    case DM_FLT64:
    decimalPlaces = 2;
    break;
  }

  XtVaSetValues(_barGraph, XcNdataType, xcType, 
		XcNlowerBound, minimum.lval,
		XcNupperBound, maximum.lval,
		XcNdecimals, decimalPlaces,
		NULL);

  setMultiplier(1.);
  
  if (addDmObject(dmObject, DmConsumeFlag) == -1)
    return;

  if (setConsumePeriod(period) == -1)
    return;

  char errorBuf[errorMsgSize];
  
  if (alarmName)
  {
    if ((_alarm = ((TiburonApp *)theApplication)->systemAlarms->
	 find(alarmName)) == NULL)
    {
      sprintf(errorBuf, "DmBarGraph() - couldn't find alarm \"%s\"",
	      alarmName);
      setError(errorBuf);
      return;
    }
  }
  else
    _alarm = NULL;
  
  if (_alarm)
  {
    _alarmDetector = new DmInputDetector("alarmDetector", _parent, 
					 _alarm->dmObject(), this);

  }
  else
    _alarmDetector = NULL;
  
  // Force update of alarm object and appropriate GUI response
  updateFromPeer(this, NULL);

  _prevValue = MAXFLOAT;
}


void DmBarGraph::updateFromPeer(DmGuiObject *peer, void *clientData)
{
  Priority priority;
  
  if (_alarm)
  {
    _alarm->update();
    priority = _alarm->priority(_alarm->value());
  }
  else
    priority = NoPriority;
  
  Pixel barColor, foreground, background;
  TiburonApp *app = (TiburonApp *)theApplication;
  app->priorityColors(priority, &foreground, &background);
  
  if (priority == NoPriority)
    barColor = _okBarColor;
  else
    barColor = background;
  

  XtVaSetValues(_barGraph,
		XcNbarForeground, barColor,
		XcNvalueForeground, foreground,
		XcNvalueBackground, background,
		NULL);
}


void DmBarGraph::setTickmarks(unsigned nTickmarks)
{
  XtVaSetValues(_barGraph, XcNscaleSegments, nTickmarks, NULL);
}


void DmBarGraph::setHorizontal()
{
  XtVaSetValues(_barGraph, XcNorient, XcHoriz, NULL);
}


void DmBarGraph::setVertical()
{
  XtVaSetValues(_barGraph, XcNorient, XcVert, NULL);
}


void DmBarGraph::setDecimalPlaces(unsigned decimalPlaces)
{
  XtVaSetValues(_barGraph, XcNdecimals, decimalPlaces);
}


void DmBarGraph::postOptions(XEvent *event)
{
  if (_alarm)
    AlarmedObject::addMenuItem(_popupMenu, _alarm);

  _popupMenu->show(event);
}


DmInt16BarGraph::DmInt16BarGraph(const char *name, Widget parent,
				 char *dmObjectName,
				 int period, 
				 char *alarmName,
				 int min, int max)
  : DmBarGraph(name, parent)
{
  char errorBuf[errorMsgSize];
  _dmObject = new DmInt16Object(dmObjectName);
  if (_dmObject->error())
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  initialize(_dmObject, period, alarmName, min, max, DM_INT16);
  
  updateGui();
}


DmInt16BarGraph::~DmInt16BarGraph() 
{
}


void DmInt16BarGraph::updateGui(DM_Item handle)
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  Int16 ivalue;
  Errno errno;
  
  if ((errno = _dmObject->read(&ivalue, &t)) != SUCCESS)
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if ((float )ivalue != _prevValue)
  {
    XcVType xcValue;
    xcValue.fval = ivalue * _multiplier;
    XcBGUpdateValue(_barGraph, &xcValue); 
  }
  
  _prevValue = (float )ivalue;
  return;
}


DmNat16BarGraph::DmNat16BarGraph(const char *name, Widget parent,
				 char *dmObjectName,
				 int period, 
				 char *alarmName,
				 unsigned min, unsigned max)
  : DmBarGraph(name, parent)
{
  char errorBuf[errorMsgSize];
  _dmObject = new DmNat16Object(dmObjectName);
  if (_dmObject->error())
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  initialize(_dmObject, period, alarmName, min, max, DM_NAT16);
  
  updateGui();
}


DmNat16BarGraph::~DmNat16BarGraph() 
{
}


void DmNat16BarGraph::updateGui(DM_Item handle)
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  Nat16 ivalue;
  Errno errno;
  
  if ((errno = _dmObject->read(&ivalue, &t)) != SUCCESS)
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if ((float )ivalue != _prevValue)
  {
    XcVType xcValue;
    xcValue.fval = ivalue * _multiplier;
    XcBGUpdateValue(_barGraph, &xcValue); 
  }
  
  _prevValue = (float )ivalue;
  return;
}



DmFlt32BarGraph::DmFlt32BarGraph(const char *name, Widget parent,
				 char *dmObjectName,
				 int period, 
				 char *alarmName,
				 float min, float max)
  : DmBarGraph(name, parent)
{
  char errorBuf[errorMsgSize];
  _dmObject = new DmFlt32Object(dmObjectName);
  if (_dmObject->error())
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  initialize(_dmObject, period, alarmName, min, max, DM_FLT32);
  
  updateGui();
}


DmFlt32BarGraph::~DmFlt32BarGraph() 
{
}


void DmFlt32BarGraph::updateGui(DM_Item handle)
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  Flt32 value;
  Errno errno;
  
  if ((errno = _dmObject->read(&value, &t)) != SUCCESS)
  {
    _dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if (value != _prevValue)
  {
    XcVType xcValue;
    xcValue.fval = _multiplier * value;
    XcBGUpdateValue(_barGraph, &xcValue); 
  }
  
  _prevValue = value;
  return;
}


