
static char PowerAllocation_id[] = "$Header: /u/oreilly/rov/tmacs/RCS/PowerAllocation.cc,v 1.4 1998/12/18 21:18:04 oreilly Exp $";

/*
$Log: PowerAllocation.cc,v $
Revision 1.4  1998/12/18 21:18:04  oreilly
*** empty log message ***

Revision 1.3  1997/05/07 17:27:29  oreilly
Delete contained DmInputDetector in destructor

Revision 1.2  97/03/20  12:30:29  12:30:29  oreilly (Thomas C. O'Reilly)
..

Revision 1.1  96/10/28  09:12:35  09:12:35  oreilly (Thomas C. O'Reilly)
Initial revision

*/
#include <values.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h>
#include "PowerAllocation.h"
#include "tiburon.h"
#include "powerDM.h"
#include "TiburonApp.h"
#include "DmErrno.h"

#define dprintf if (debug) fprintf

XtResource PowerAllocation::_resources[] = 
{
  {
    "barWidth",
    "BarWidth",
    XmRInt,
    sizeof(int),
    XtOffset(PowerAllocation *, _barWidth),
    XmRString,
    "100"
  },

  {
    "barHeight",
    "BarHeight",
    XmRInt,
    sizeof(int),
    XtOffset(PowerAllocation *, _barHeight),
    XmRString,
    "18"
  }
};


PowerAllocation::PowerAllocation(const char *name, Widget parent, int period)
  : DmGuiObject(name, parent)
{
  _baseWidget = XtCreateWidget(name, xmFormWidgetClass, parent, NULL, 0);
  installDestroyHandler();

  getResources(_resources, XtNumber(_resources));

  _maxAvailableDetector = NULL;
  
  const float minPower = 0.;
  const float maxPower = 15.;
  const int leftBarPosition = 40;
  const int rightBarPosition = 80;
  const int valueOffset = 2;
  
  Widget label;

  label = 
    XtVaCreateManagedWidget("lightsLabel", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_FORM,
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _lights = new BarGuage("lights", _baseWidget, minPower, maxPower);
  _lights->setOrientation(XmHORIZONTAL);
  XtVaSetValues(_lights->baseWidget(), 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, leftBarPosition,
		XmNrightAttachment, XmATTACH_POSITION,
		XmNrightPosition, rightBarPosition,
		XmNtopAttachment, XmATTACH_FORM,
		XmNwidth, _barWidth, XmNheight, _barHeight, NULL);

  _lights->show();

  _lightsValue = new DynamicLabel("lightsValue", _baseWidget, 
				  XmALIGNMENT_BEGINNING);
  XtVaSetValues(_lightsValue->baseWidget(),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _lights->baseWidget(),
		XmNleftOffset, valueOffset,
		NULL);
  
  _lightsValue->show();
  
  label = 
    XtVaCreateManagedWidget("hotelLabel", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _lights->baseWidget(),
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _hotel = new BarGuage("hotel", _baseWidget, minPower, maxPower);
  _hotel->setOrientation(XmHORIZONTAL);
  XtVaSetValues(_hotel->baseWidget(), 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, leftBarPosition,
		XmNrightAttachment, XmATTACH_POSITION,
		XmNrightPosition, rightBarPosition,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _lights->baseWidget(),
		XmNwidth, _barWidth, XmNheight, _barHeight, NULL);

  _hotel->show();

  _hotelValue = new DynamicLabel("hotelValue", _baseWidget,
				 XmALIGNMENT_BEGINNING);
  XtVaSetValues(_hotelValue->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _lights->baseWidget(),
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _hotel->baseWidget(),
		XmNleftOffset, valueOffset,
		NULL);

  _hotelValue->show();
  
  label = 
    XtVaCreateManagedWidget("toolSledLabel", xmLabelWidgetClass, 
			    _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _hotel->baseWidget(),
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _toolSled = new BarGuage("toolSled", _baseWidget, minPower, maxPower);
  _toolSled->setOrientation(XmHORIZONTAL);
  XtVaSetValues(_toolSled->baseWidget(), 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, leftBarPosition,
		XmNrightAttachment, XmATTACH_POSITION,
		XmNrightPosition, rightBarPosition,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _hotel->baseWidget(),
		XmNwidth, _barWidth, XmNheight, _barHeight, NULL);

  _toolSled->show();

  _toolSledValue = new DynamicLabel("toolSledValue", _baseWidget,
				    XmALIGNMENT_BEGINNING);
  XtVaSetValues(_toolSledValue->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _hotel->baseWidget(),
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _toolSled->baseWidget(),
		XmNleftOffset, valueOffset,
		NULL);

  _toolSledValue->show();
  
  label = 
    XtVaCreateManagedWidget("thrustersLabel", xmLabelWidgetClass, 
			    _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _toolSled->baseWidget(),
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _thrusters = new BarGuage("thrusters", _baseWidget, minPower, maxPower);
  _thrusters->setOrientation(XmHORIZONTAL);
  XtVaSetValues(_thrusters->baseWidget(), 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, leftBarPosition,
		XmNrightAttachment, XmATTACH_POSITION,
		XmNrightPosition, rightBarPosition,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _toolSled->baseWidget(),
		XmNwidth, _barWidth, XmNheight, _barHeight, NULL);

  _thrusters->show();

  _thrustersValue = new DynamicLabel("thrustersValue", _baseWidget,
				     XmALIGNMENT_BEGINNING);
  XtVaSetValues(_thrustersValue->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _toolSled->baseWidget(),
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _thrusters->baseWidget(),
		XmNleftOffset, valueOffset,
		NULL);

  _thrustersValue->show();
  
  label = 
    XtVaCreateManagedWidget("totalLabel", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _thrusters->baseWidget(),
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _total = new BarGuage("total", _baseWidget, minPower, maxPower);
  _total->setOrientation(XmHORIZONTAL);
  XtVaSetValues(_total->baseWidget(), 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, leftBarPosition,
		XmNrightAttachment, XmATTACH_POSITION,
		XmNrightPosition, rightBarPosition,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _thrusters->baseWidget(),
		XmNwidth, _barWidth, XmNheight, _barHeight, NULL);
  
  _total->show();

  _totalValue = new DynamicLabel("totalValue", _baseWidget,
				 XmALIGNMENT_BEGINNING);
  XtVaSetValues(_totalValue->baseWidget(),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, _thrusters->baseWidget(),
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, _total->baseWidget(),
		XmNleftOffset, valueOffset,
		NULL);

  _totalValue->show();

  _maxAvailable =
    XtVaCreateManagedWidget("maxAvailable", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _total->baseWidget(),
			    XmNtopOffset, 5,
			    XmNleftAttachment, XmATTACH_FORM,
			    NULL);

  _sufficient = 
    XtVaCreateManagedWidget("sufficient", xmLabelWidgetClass, _baseWidget,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _maxAvailable,
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    NULL);

  XtManageChild(_baseWidget);

  char itemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  char *namePtr = itemName;
  
  strcpy(namePtr, LIGHTS_PWR_ALLOC_DM);
  _dmLights = new DmNat16Object(namePtr);
  if (_dmLights->error())
  {
    _dmLights->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if (addDmObject(_dmLights, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, HOTEL_PWR_ALLOC_DM);
  _dmHotel = new DmNat16Object(namePtr);
  if (_dmHotel->error())
  {
    _dmHotel->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if (addDmObject(_dmHotel, DmConsumeFlag) == -1)
    return;
  
  strcpy(namePtr, TOOLS_PWR_ALLOC_DM);
  _dmToolSled = new DmNat16Object(namePtr);
  if (_dmToolSled->error())
  {
    _dmToolSled->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if (addDmObject(_dmToolSled, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, THRUSTERS_PWR_ALLOC_DM);
  _dmThrusters = new DmNat16Object(namePtr);
  if (_dmThrusters->error())
  {
    _dmThrusters->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  if (addDmObject(_dmThrusters, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, THRUSTERS_PWR_OK_DM);
  _dmSufficient = new DmBooleanObject(namePtr);
  if (_dmSufficient->error())
  {
    _dmSufficient->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }

  if (addDmObject(_dmSufficient, DmConsumeFlag) == -1)
    return;
  
  strcpy(namePtr, MAX_PWR_AVAIL_DM);
  _dmMaxAvailable = new DmNat16Object(namePtr);
  if (_dmMaxAvailable->error())
  {
    _dmMaxAvailable->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  
  _maxAvailableDetector = 
    new DmInputDetector("maxAvailableDetector", parent, _dmMaxAvailable, this);
  
  if (setConsumePeriod(period) == -1)
    return;

  _prevLights = _prevHotel = _prevToolSled = _prevThrusters = MAXSHORT;

  _prevTotal = MAXFLOAT;
  _prevSufficient = 999;
  
  updateFromPeer(this, NULL);
  
  updateGui();
}


void PowerAllocation::updateGui(DM_Item handle)
{
  DM_Time t;
  char errorBuf[errorMsgSize];
  Nat16 ivalue;
  Nat16 total = 0;
  Flt32 value;
  Errno err;
  MBool debug = FALSE;

  if ((err = _dmLights->read(&ivalue, &t)) != SUCCESS)
  {
    sprintDmError(err, "updateGui() - error reading _dmLights", errorBuf);
    setError(errorBuf);
  }
  else 
  {
    total += ivalue;
    if (abs(ivalue - _prevLights) > 100)
    {
      value = (float )ivalue / 1000.;  
      _lights->set(value);
      setValueString(value, _lightsValue);
      _prevLights = ivalue;    
    }
  }
  
  if ((err = _dmHotel->read(&ivalue, &t)) != SUCCESS)
  {
    sprintDmError(err, "updateGui() - error reading _dmHotel", errorBuf);
    setError(errorBuf);
  }
  else 
  {
    total += ivalue;
    if (abs(ivalue - _prevHotel) > 100)
    {
      value = (float )ivalue / 1000.;
      _hotel->set(value);
      setValueString(value, _hotelValue);
      _prevHotel = ivalue;
    }
  }
  
  if ((err = _dmToolSled->read(&ivalue, &t)) != SUCCESS)
  {
    sprintDmError(err, "updateGui() - error reading _dmToolsled", errorBuf);
    setError(errorBuf);
  }
  else
  {
    total += ivalue;
    if (abs(ivalue - _prevToolSled) > 100)
    {
      value = (float )ivalue / 1000.;
      _toolSled->set(value);
      setValueString(value, _toolSledValue);
      _prevToolSled = ivalue;
    }
  }
  
  if ((err = _dmThrusters->read(&ivalue, &t)) != SUCCESS)
  {
    sprintDmError(err, "updateGui() - error reading _dmThrusters", errorBuf);
    setError(errorBuf);
  }
  else
  {
    total += ivalue;
    if (abs(ivalue - _prevThrusters) > 100)
    {
      value = (float )ivalue / 1000.;
      _thrusters->set(value);
      setValueString(value, _thrustersValue);
      _prevThrusters = ivalue;
    }
  }
  dprintf(stderr, "PowerAllocation::updateGui() - total=%d, prev=%.0f\n", 
	  total, _prevTotal);

  if (abs(total - _prevTotal) > 100)
  {
    value = (float )total / 1000.; 
    _total->set(value);
    setValueString(value, _totalValue);
    _prevTotal = total;
  }

  MBool sufficient;
  
  if ((err = _dmSufficient->read(&sufficient, &t)) != SUCCESS)
  {
    sprintDmError(err, "updateGui() - error reading _dmLights", errorBuf);
    setError(errorBuf);
  }  
  else if (sufficient != _prevSufficient)
  {
    XmString xmstr;
    Pixel foreground, background;
    
    if (!sufficient)
    {
      xmstr = XmStringCreateSimple("Power Limited");
      ((TiburonApp *)theApplication)->priority1Colors(&foreground,
						      &background);
    }
    else
    {
      xmstr = XmStringCreateSimple("");
      ((TiburonApp *)theApplication)->okColors(&foreground,
					       &background);
    }
    
    XtVaSetValues(_sufficient, XmNlabelString, xmstr, 
		  XmNforeground, foreground, XmNbackground, background, 
		  NULL);

    XmStringFree(xmstr);
    
    _prevSufficient = sufficient;
  }
}


void PowerAllocation::updateFromPeer(DmGuiObject *peer, void *clientData)
{
  Nat16 value;
  DM_Time t;
  char errorBuf[errorMsgSize];
  Errno err;
  MBool debug = FALSE;

  // Read max available power
  if ((err = _dmMaxAvailable->read(&value, &t)) != SUCCESS)
  { 
    sprintDmError(err, 
		  "updateFromPeer() - error reading _dmMaxAvailable", 
		  errorBuf);

    setError(errorBuf);
    return;
  }
  float maxAvailable = (float )value / 1000.;

  char buf[100];
  sprintf(buf, "Max Avail: %4.1f KW", maxAvailable);
  XmString xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_maxAvailable, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);
  
  _lights->setRange(0., maxAvailable);
  _hotel->setRange(0., maxAvailable);
  _toolSled->setRange(0., maxAvailable);
  _thrusters->setRange(0., maxAvailable);
  _total->setRange(0., maxAvailable);

  // Reset prev values to force display update
  _prevLights = _prevHotel = _prevToolSled = _prevThrusters = MAXSHORT;
  _prevTotal = MAXFLOAT;

  updateGui();
  
}


void PowerAllocation::setValueString(Flt32 value, DynamicLabel *label)
{
  char buf[100];
  sprintf(buf, "%3.1f", value);
  label->setText(buf);
}
