
static char PowerBus_id[] = "$Header: /u/oreilly/rov/tmacs/RCS/PowerBus.cc,v 1.5 1998/05/18 20:18:09 oreilly Exp $";

/*
$Log: PowerBus.cc,v $
Revision 1.5  1998/05/18 20:18:09  oreilly
*** empty log message ***

Revision 1.4  1997/10/03 09:32:03  oreilly
*** empty log message ***

Revision 1.3  97/03/20  12:30:32  12:30:32  oreilly (Thomas C. O'Reilly)
..

Revision 1.2  96/10/28  09:12:36  09:12:36  oreilly (Thomas C. O'Reilly)
*** empty log message ***

*/
#include <ctype.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include "PowerBus.h"

PowerSwitchNode::PowerSwitchNode(const char *name, 
				 const char *switchName,
				 const char *switchDmPrefix,
				 int buttonWidth, int buttonHeight, 
				 int period, Boolean showCurrent,
				 Boolean readOnly)
  : VkNode(name, switchName)
{
  _switchName = strdup(switchName);

  if (switchDmPrefix)
    _switchDmPrefix = strdup(switchDmPrefix);
  else
    _switchDmPrefix = NULL;
  
  _buttonWidth = buttonWidth;
  _buttonHeight = buttonHeight;
  _period = period;
  _showCurrent = showCurrent;
  _powerSwitch = NULL;
  _powerStatus = NULL;
  _readOnly = readOnly;
}


PowerSwitchNode::~PowerSwitchNode()
{
  free(_switchName);
  free(_switchDmPrefix);
  delete _powerSwitch;
  delete _powerStatus;
}


void PowerSwitchNode::build(Widget parent)
{
  if (_readOnly)
  {
    _powerStatus = new PowerSwitchStatus(name(), parent, _switchDmPrefix,
					 _switchName, 
					 _buttonWidth, _buttonHeight,
					 _period, _showCurrent);
  }
  else
    _powerSwitch = new PowerSwitchGui(name(), parent, _switchDmPrefix,
				      _switchName, _buttonWidth, _buttonHeight,
				      _period, _showCurrent);

  _powerSwitch->show();
  _baseWidget = _powerSwitch->baseWidget();
}


MotorSwitchNode::MotorSwitchNode(const char *name, 
				 const char *switchName,
				 const char *switchDmPrefix,
				 const char *enableDmPrefix,
				 int buttonWidth,
				 int buttonHeight,
				 int period)
  : PowerSwitchNode(name, switchName, switchDmPrefix, buttonWidth,
		    buttonHeight, period, True, False)
{
  _enableDmPrefix = strdup(enableDmPrefix);
}


MotorSwitchNode::~MotorSwitchNode()
{
  if (_enableDmPrefix) free(_enableDmPrefix);
}


void MotorSwitchNode::build(Widget parent)
{
  _powerSwitch = new MotorSwitchGui(name(), parent, _switchDmPrefix,
				    _enableDmPrefix,
				    _switchName, _buttonWidth, _buttonHeight,
				    _period);

  _powerSwitch->show();
  _baseWidget = _powerSwitch->baseWidget();
}


SwitchGroupNode::SwitchGroupNode(
				 const char *name,
				 int buttonWidth,
				 int buttonHeight,
				 int period
				 )
  : VkNode(name, name)
{
  _buttonWidth = buttonWidth;
  _buttonHeight = buttonHeight;
  _period = period;
}


SwitchGroupNode::~SwitchGroupNode()
{
  int i;
  
  for (i = 0; i < _switchDescriptions.size(); i++)
  { 
    SwitchDescription *description;
    _switchDescriptions.get(i, &description);
    delete description;
  }
}


void SwitchGroupNode::addSwitch(const char *switchName, 
				const char *dmSwitchPrefix,
				Boolean readOnly)
{
  char *namePtr;
  char *prefixPtr;
  
  SwitchDescription *description = new SwitchDescription();
  description->name = strdup(switchName);
  description->dmPrefix = strdup(dmSwitchPrefix);
  description->readOnly = readOnly; 
  _switchDescriptions.add(&description);
}


void SwitchGroupNode::build(Widget parent)
{
  Widget mgr = XtVaCreateWidget(_name, xmFormWidgetClass, parent, NULL);
  
  PowerSwitchGui *powerSwitch;
  PowerSwitchStatus *powerStatus;
  Widget prevWidget;
  
  for (int i = 0; i < _switchDescriptions.size(); i++)
  {
    char componentName[100];
    DmGuiObject *guiObject;
    
    char *namePtr, *prefixPtr;
    SwitchDescription *description;
    _switchDescriptions.get(i, &description);
    
    sprintf(componentName, "switch%02d", i);
    
    if (description->readOnly)
    {
      guiObject = description->powerStatus = 
	new PowerSwitchStatus(componentName, mgr, 
			      description->dmPrefix, 
			      description->name,
			      _buttonWidth, 
			      _buttonHeight,
			      _period);

    }
    else
    {
      guiObject = description->powerSwitch = 
	new PowerSwitchGui(componentName, mgr, 
			   description->dmPrefix,
			   description->name,
			   _buttonWidth, _buttonHeight,
			   _period);

    }
    
    if (i == 0)
      XtVaSetValues(guiObject->baseWidget(),
		    XmNleftAttachment, XmATTACH_FORM,
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);
    else
      XtVaSetValues(guiObject->baseWidget(),
		    XmNleftAttachment, XmATTACH_WIDGET,
		    XmNleftWidget, prevWidget,
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);

    guiObject->show();
    
    prevWidget = guiObject->baseWidget();
    _baseWidget = mgr;
    
  }
}


XtResource PowerBus::_resources[] = 
{
  {
    "onColor",
    "OnColor",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(PowerBus *, _onColor),
    XmRString, 
    "green"
  },
  {
    "offColor",
    "OffColor",
    XtRPixel,
    sizeof(Pixel),
    XtOffset(PowerBus *, _offColor),
    XmRString, 
    "black"
  }
};


PowerBus::PowerBus(const char *name, Widget parent, Bus *bus, 
		   int buttonWidth, int buttonHeight)
  : VkComponent(name)
{
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);
  installDestroyHandler();
  getResources(_resources, XtNumber(_resources));

  _graph = new VkGraph("graph", _baseWidget);
  XtVaSetValues(_graph->baseWidget(),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
  
  // Create nodes and add to graph
  createNodes(bus, NULL, 0, buttonWidth, buttonHeight);

  _graph->displayAll();
  _graph->doLayout();
  XtUnmanageChild(_graph->workArea());
  _graph->show();
  XtUnmanageChild(_graph->workArea());
}


PowerBus::~PowerBus()
{
  VkNode *node;
  for (int i = 0; i < _nodes.size(); i++)
  {
    _nodes.get(i, &node);
    delete node;
  }
}


void PowerBus::createNodes(VehicleComponent *parent, 
			   VkNode *parentNode, int index,
			   int buttonWidth, int buttonHeight)
{
  char nodeName[50];
  VehicleComponent **child;
  
  if (!parentNode) 
  {
    // Make a node for the bus
    sprintf(nodeName, "node%04d", ++index);
    parentNode = new VkNode(nodeName, parent->name());
    XtVaSetValues(parentNode->baseWidget(), 
		  XmNbackground, _onColor, 
		  NULL);
    
    _graph->add(parentNode);
  }
  
  VkNode *cNode;

  SListIter<VehicleComponent *> children(parent->childList);

  if (parent->type() == VehicleComponent::VicorSwitchType &&
      !parent->hasGrandChildren())
  {
    /* If parent is a Vicor, and has no grandchildren, then display
       children as a group */
    SwitchGroupNode *switchGroup = NULL;
    
    children.reset();
    while (child = children.next())
    {
      if (!switchGroup)
      {
	sprintf(nodeName, "node%04d", ++index);
	switchGroup = new SwitchGroupNode(nodeName, 
					  buttonWidth, buttonHeight,
					  500);

	cNode = (VkNode *)switchGroup;
	_nodes.add(&cNode);
	_graph->add(parentNode, cNode);
      }
      Switch *aSwitch = (Switch *)(*child);
      switchGroup->addSwitch((*child)->name(), aSwitch->dmSwitchPrefix(),
			     aSwitch->readOnly());
    }
    
    /* No recursion necessary, since parent has no grandchildren */
    return;
  }

  children.reset();
  while (child = children.next())
  {
    if ((*child)->isSwitch())
    {
      sprintf(nodeName, "node%04d", ++index);
    
      PowerSwitchNode *childNode;
      Switch *aSwitch;
      MotorSwitch *motorSwitch;
      
      switch ((*child)->type())
      {
	case VehicleComponent::MotorSwitchType:
	motorSwitch = (MotorSwitch *)(*child);
	childNode = 
	  new MotorSwitchNode(nodeName, (*child)->name(),
			      motorSwitch->dmSwitchPrefix(),
			      motorSwitch->dmEnablePrefix(),
			      buttonWidth, buttonHeight, 500);

	cNode = (VkNode *)childNode;
	break;


	default:
	aSwitch = (Switch *)(*child);
	Boolean showCurrent;
	
	if ((*child)->type() == VehicleComponent::VicorSwitchType)
	  showCurrent = False;
	else
	  showCurrent = True;
	
	childNode = 
	  new PowerSwitchNode(nodeName, (*child)->name(),
			      aSwitch->dmSwitchPrefix(),
			      buttonWidth, buttonHeight, 500, 
			      showCurrent, aSwitch->readOnly());

	cNode = (VkNode *)childNode;
	_nodes.add(&cNode);
	_graph->add(parentNode, cNode);
	break;
      }
      _nodes.add(&cNode);
      _graph->add(parentNode, cNode);
      
      createNodes(*child, cNode, ++index, buttonWidth, buttonHeight); 
    }
    else
      createNodes(*child, parentNode, ++index, buttonWidth, buttonHeight); 

  }
}


void PowerBus::afterRealizeHook()
{
  _graph->displayAll();
  _graph->doLayout();
  _graph->show();

  // Hide graph controls
  XtUnmanageChild(_graph->workArea());
}  



SwitchGroupNode::SwitchDescription::SwitchDescription()
{
  name = dmPrefix = NULL;
  powerSwitch = NULL;
  powerStatus = NULL;
  readOnly = False;
}


SwitchGroupNode::SwitchDescription::~SwitchDescription()
{
  free(name);
  free(dmPrefix);
  delete powerSwitch;
  delete powerStatus;
}
