#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/Separator.h>
#include <Xm/ScrolledW.h>
#include <Vk/VkInfoDialog.h>
#include <Vk/VkErrorDialog.h>
#include "VspPage.h"
#include "TableForm.h"
#include "TiburonApp.h"
#include "Micro.h"
#include "DmErrno.h"
#include "stringUtils.h"
#include "vspDm.h"

#define dprintf if (debug) fprintf
#define VspEntryColumns 8

VspEntry::VspEntry(const char *name, 
		   Widget parent, const char *dmPrefix,
		   VspPage *vspPage)
  : DmGuiObject(name, parent)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, NULL);
  
  installDestroyHandler();
  _dmPrefix = strdup(dmPrefix);
  _vspPage = vspPage;
  
  TableRowForm *mgr = new TableRowForm("mgr", _baseWidget, VspEntryColumns);
  
  Widget label = 
    XtVaCreateManagedWidget(name, xmLabelWidgetClass, 
			    mgr->baseWidget(), NULL);
  mgr->append(label);

  _port = 
    XtVaCreateManagedWidget("port", xmLabelWidgetClass,
			    mgr->baseWidget(), NULL);

  mgr->append(_port);
  
  _baud = 
    XtVaCreateManagedWidget("baud", xmLabelWidgetClass,
			    mgr->baseWidget(), NULL);
  
  mgr->append(_baud);

  _dataBitsStopBitsParity = 
    XtVaCreateManagedWidget("dataBitsStopBitsParity", xmLabelWidgetClass,
			    mgr->baseWidget(), NULL);
  
  mgr->append(_dataBitsStopBitsParity);


  _protocol = 
    XtVaCreateManagedWidget("protocol", xmLabelWidgetClass,
			    mgr->baseWidget(), NULL);
  
  mgr->append(_protocol);

  _handshake = 
    XtVaCreateManagedWidget("handshake", xmLabelWidgetClass,
			    mgr->baseWidget(), NULL);
  
  mgr->append(_handshake);


  _breakButton = 
    XtVaCreateManagedWidget("breakButton", xmPushButtonWidgetClass,
			    mgr->baseWidget(), NULL);
  
  mgr->append(_breakButton);

  XtAddCallback(_breakButton, XmNarmCallback,
		&VspEntry::breakCallback, (XtPointer )this);

  XtAddCallback(_breakButton, XmNdisarmCallback,
		&VspEntry::breakCallback, (XtPointer )this);

  // Get colors to use in re-drawing "break" button
  XtVaGetValues(_breakButton,
		XmNarmColor, &_armColor,
		XmNbackground, &_background,
		XmNtopShadowColor, &_lightEdgeColor, 
		XmNbottomShadowColor, &_darkEdgeColor,
		NULL);


  Widget editButton = 
    XtVaCreateManagedWidget("editButton", xmPushButtonWidgetClass,
			    mgr->baseWidget(), NULL);
  
  XtAddCallback(editButton, XmNactivateCallback,
		&VspEntry::editCallback, (XtPointer )this);

  mgr->append(editButton);
  
  mgr->show();

  char itemName[MaxDmNameLen];
  strcpy(itemName, dmPrefix);
  
  char *namePtr = itemName + strlen(itemName);

  strcpy(namePtr, VSP_PORT_DM);
  dmPort = new DmNat16Object(itemName);
  
  if (addDmObject(dmPort, DmConsumeFlag) == -1)
    return;

  strcpy(namePtr, VSP_BAUD_DM);
  dmBaud = new DmNat16Object(itemName);

  if (addDmObject(dmBaud, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_DATA_BITS_DM);
  dmDataBits = new DmNat16Object(itemName);

  if (addDmObject(dmDataBits, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_STOP_BITS_DM);
  dmStopBits = new DmNat16Object(itemName);

  if (addDmObject(dmStopBits, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_PARITY_DM);
  dmParity = new DmNat16Object(itemName);

  if (addDmObject(dmParity, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_HANDSHAKE_DM);
  dmHandshake = new DmBooleanObject(itemName);

  if (addDmObject(dmHandshake, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_PROTOCOL_DM);
  dmProtocol = new DmNat16Object(itemName);

  if (addDmObject(dmProtocol, DmConsumeFlag | DmProvideFlag) == -1)
    return;
  
  strcpy(namePtr, VSP_BREAK_DM);
  dmBreak = new DmNat16Object(itemName);

  if (addDmObject(dmBreak, DmProvideFlag | DmConsumeFlag) == -1)
    return;
  
  if (setConsumePeriod(AperiodicGuaranteed) == -1)
    return;

  _breakArmed = False;
  
  updateGui();
}


VspEntry::~VspEntry()
{
  free((void *)_dmPrefix);
}


void VspEntry::updateGui(DM_Item handle)
{
  Boolean debug = False;
  dprintf(stderr, "VspEntry::updateGui()\n");

  DM_Time t;
  Errno errno;
  char errorBuf[errorMsgSize];
  Nat16 value;
  char buf[100];
  XmString xmstr;
  
  if ((errno = dmPort->read(&value, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading port", errorBuf);
    setError(errorBuf);
  }
  sprintf(buf, "%d", value);
  xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_port, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);

  if ((errno = dmBaud->read(&value, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading baud", errorBuf);
    setError(errorBuf);
  }
  sprintf(buf, "%d", value);
  xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_baud, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);
  Nat16 dataBits, stopBits, parity;
  
  if ((errno = dmDataBits->read(&dataBits, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading databits", errorBuf);
    setError(errorBuf);
  }
  
  if ((errno = dmStopBits->read(&stopBits, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading stopbits", errorBuf);
    setError(errorBuf);
  }

  if ((errno = dmParity->read(&parity, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading baud", errorBuf);
    setError(errorBuf);
  }
  char *parityMnem;
  switch (parity)
  {
    case VSP_NO_PARITY:
    parityMnem = "none";
    break;
    
    case VSP_ODD_PARITY:
    parityMnem = "odd";
    break;
    
    case VSP_EVEN_PARITY:
    parityMnem = "even";
    break;

    default:
    parityMnem = "Unknown!";
  }
  
  sprintf(buf, "%d, %d, %s", dataBits, stopBits, parityMnem);
  xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_dataBitsStopBitsParity, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);

  MBool handshake;
  
  if ((errno = dmHandshake->read(&handshake, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading handshake", errorBuf);
    setError(errorBuf);
  }
  if (handshake)
    strcpy(buf, "on");
  else
    strcpy(buf, "off");

  xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_handshake, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);

  if ((errno = dmProtocol->read(&value, &t)) != SUCCESS)
  {
    sprintDmError(errno, "VspEntry::updateGui(), reading protocol", errorBuf);
    setError(errorBuf);
  }

  char *protocolMnem;
  
  switch (value)
  {
    case VSP_RS232_PROTOCOL:
    protocolMnem = "RS-232";
    break;
    
    case VSP_RS485_PROTOCOL:
    protocolMnem = "RS-485";
    break;
    
    default:
    protocolMnem = "Unknown!";
  }
  
  xmstr = XmStringCreateSimple(protocolMnem);
  XtVaSetValues(_protocol, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);

  /* Only reflect "send break" condition on GUI if this user is
     not pressing the button */
  if (!_breakArmed)
  {
    if ((errno = dmBreak->read(&value, &t)) != SUCCESS)
    {
      sprintDmError(errno, 
		    "VspEntry::updateGui(), reading protocol", errorBuf);
      setError(errorBuf);
    }    
    if (value)
    {
      // Display button as "pressed in"
      XtVaSetValues(_breakButton,
		    XmNbackground, _armColor,
		    XmNtopShadowColor, _darkEdgeColor, 
		    XmNbottomShadowColor, _lightEdgeColor, 
		    NULL);
    }
    else
    {
      // Display button as "out"
      XtVaSetValues(_breakButton,
		    XmNbackground, _background, 
		    XmNtopShadowColor, _lightEdgeColor, 
		    XmNbottomShadowColor, _darkEdgeColor, 
		    NULL);
    }
  }
}


void VspEntry::breakControl(MBool sendBreak)
{
  DM_Time t;
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  Nat16 val;
  
  if (sendBreak)
  {
    _breakArmed = True;
    val = 1;
  }
  else
  {
    _breakArmed = False;
    val = 0;
  }
  
  dmBreak->write(val, &t);
}


void VspEntry::editCallback(Widget w,
			    XtPointer clientData,
			    XtPointer callData)			    
{
  const VspEntry *obj = (VspEntry *)clientData;
  obj->_vspPage->createConfigDialog(obj);
}


void VspEntry::breakCallback(Widget w,
			     XtPointer clientData,
			     XtPointer callData)
{
  Boolean debug = False;
  dprintf(stderr, "VspEntry::breakCallback()\n");

  VspEntry *obj = (VspEntry *)clientData;
  
  XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)callData;
  MBool sendBreak;
  
  if (cbs->reason == XmCR_ARM)
    sendBreak = TRUE;
  else if (cbs->reason == XmCR_DISARM)
    sendBreak = FALSE;

  obj->breakControl(sendBreak);
}



MnemonicValue VspPage::baudMnemonicValue[] = 
{
  "1200", 1200,
  "2400", 2400,
  "4800", 4800,
  "9600", 9600,
  "38400", 38400,
  NULL, NULL
};

MnemonicValue VspPage::dataBitsMnemonicValue[] = 
{
  "six", 6,
  "seven", 7,
  "eight", 8,
  NULL, NULL
};

MnemonicValue VspPage::stopBitsMnemonicValue[] = 
{
  "zero", 0,
  "one", 1,
  "two", 2,
  NULL, NULL
};

MnemonicValue VspPage::parityMnemonicValue[] = 
{
  "none", 0,
  "odd", 1,
  "even", 2,
  NULL, NULL
};

MnemonicValue VspPage::protocolMnemonicValue[] = 
{
  "RS232", 0,
  "RS485", 1,
  NULL, NULL
};


MnemonicValue VspPage::handshakeMnemonicValue[] = 
{
  "off", 0,
  "on", 1,
  NULL, NULL
};



VspConfiguration::VspConfiguration(const char *name, Widget parent,
				   const VspEntry *vspEntry)
  : VkComponent(name)
{
  _baseWidget = XtVaCreateWidget(name, xmRowColumnWidgetClass, parent, 
				 XmNorientation, XmVERTICAL,
				 NULL);
  
  installDestroyHandler();

  _vspEntry = vspEntry;
  
  char buf[100];
  sprintf(buf, "IBC \"%s\", VSP port %d", name, 0);
  XmString xmstr = XmStringCreateSimple(buf);
  
  Widget label = 
    XtVaCreateManagedWidget("hdr", xmLabelWidgetClass, _baseWidget, 
			    XmNlabelString, xmstr,
			    NULL);

  XmStringFree(xmstr);
  
  Widget mgr = 
    XtVaCreateWidget("mgr", xmRowColumnWidgetClass, _baseWidget,
		     XmNorientation, XmHORIZONTAL, NULL);
  
  _baud = createMenu("baud", mgr, VspPage::baudMnemonicValue);
  _dataBits = createMenu("dataBits", mgr, VspPage::dataBitsMnemonicValue);
  _stopBits = createMenu("stopBits", mgr, VspPage::stopBitsMnemonicValue);
  _parity = createMenu("parity", mgr, VspPage::parityMnemonicValue);
  _protocol = createMenu("protocol", mgr, VspPage::protocolMnemonicValue);
  _handshake = createMenu("handshake", mgr, VspPage::handshakeMnemonicValue);

  Nat16 nat16Value;
  MBool boolValue;
  DM_Time t;
  int index;
  
  _vspEntry->dmBaud->read(&nat16Value, &t);
  index = VspPage::valueToIndex(VspPage::baudMnemonicValue, nat16Value);
  _baud->set(index);
  
  _vspEntry->dmDataBits->read(&nat16Value, &t);
  index = VspPage::valueToIndex(VspPage::dataBitsMnemonicValue, nat16Value);
  _dataBits->set(index);

  _vspEntry->dmStopBits->read(&nat16Value, &t);
  index = VspPage::valueToIndex(VspPage::stopBitsMnemonicValue, nat16Value);
  _stopBits->set(index);

  _vspEntry->dmParity->read(&nat16Value, &t);
  index = VspPage::valueToIndex(VspPage::parityMnemonicValue, nat16Value);
  _parity->set(index);

  _vspEntry->dmProtocol->read(&nat16Value, &t);
  index = VspPage::valueToIndex(VspPage::protocolMnemonicValue, nat16Value);
  _protocol->set(index);

  _vspEntry->dmHandshake->read(&boolValue, &t);
  index = VspPage::valueToIndex(VspPage::handshakeMnemonicValue, boolValue);
  _handshake->set(index);
  
  XtManageChild(mgr);

  return;
}


VspConfiguration::~VspConfiguration()
{
  delete _baud;
  delete _dataBits;
  delete _stopBits;
  delete _parity;
  delete _protocol;
  delete _handshake;
}


VkOptionMenu *VspConfiguration::createMenu(const char *name, Widget parent,
					   MnemonicValue *mnemonicValue)
{
  VkOptionMenu *menu = new VkOptionMenu(parent, name);

  for (MnemonicValue *ptr = mnemonicValue; 
       ptr->mnemonic != NULL; 
       ptr++)
  {
    menu->addAction(ptr->mnemonic);
  }
  
  return menu;
}


int VspConfiguration::save()
{
  Boolean debug = False;
  dprintf(stderr, "VspConfiguration::save()\n");

  // Read user-input parameters and write to DataManager
  int itemNo;
  Errno errno;
  Boolean error = False;
  Nat16 nat16Value;
  char errorBuf[100];

  DM_Time t;
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  itemNo = _baud->getIndex();
  nat16Value = (Nat16 )VspPage::baudMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmBaud->write(nat16Value, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing baud",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }
  
  itemNo = _dataBits->getIndex();
  nat16Value = (Nat16 )VspPage::dataBitsMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmDataBits->write(nat16Value, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing dataBits",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }

  itemNo = _stopBits->getIndex();
  nat16Value = (Nat16 )VspPage::stopBitsMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmStopBits->write(nat16Value, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing stopBits",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }


  itemNo = _parity->getIndex();
  nat16Value = (Nat16 )VspPage::parityMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmParity->write(nat16Value, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing parity",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }

  itemNo = _protocol->getIndex();
  nat16Value = (Nat16 )VspPage::protocolMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmProtocol->write(nat16Value, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing protocol",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }

  itemNo = _handshake->getIndex();

  MBool boolValue = (MBool )VspPage::handshakeMnemonicValue[itemNo].value;
  
  if ((errno = _vspEntry->dmHandshake->write(boolValue, &t)) != SUCCESS)
  { 
    sprintDmError(errno, "VspConfiguration::save() - error writing handshake",
		  errorBuf);
    
    theErrorDialog->postAndWait(errorBuf);
    return -1;
  }

  return 0;
}


VspConfigDialog::VspConfigDialog(const char *name, const VspEntry *vspEntry )
  : VkGenericDialog(name)
{
  _vspEntry = vspEntry;
}


VspConfigDialog::~VspConfigDialog()
{
  delete _configuration;
}


Widget VspConfigDialog::createDialog(Widget parent)
{
  Widget base = VkGenericDialog::createDialog(parent);
  
  _configuration = new VspConfiguration(_vspEntry->name(), base, _vspEntry);
  _configuration->show();
  return base;
}


void VspConfigDialog::okayCallback(Widget w, 
				   XtPointer clientData,
				   XtPointer callData)
{
  VspConfigDialog *obj = (VspConfigDialog *)clientData;
  obj->_configuration->save();
}


VspPage::VspPage(const char *name, Widget parent)
{
  Boolean debug = False;
  
  _baseWidget = XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL);

  installDestroyHandler();
  
  _configDialog = NULL;
  _timer = NULL;
  
  TableRowForm *mgr = 
    new TableRowForm("header", _baseWidget, VspEntryColumns);

  XtVaSetValues(mgr->baseWidget(),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		NULL);

  Widget label;

  char *headers[VspEntryColumns] = 
  {
    "name", "port", "baud", "dataBitsStopBitsParity", "protocol", "handshake",
    "break", "edit"
  };
  
  for (int i = 0; i < VspEntryColumns; i++)
  {
    label = 
      XtVaCreateManagedWidget(headers[i], xmLabelWidgetClass, 
			      mgr->baseWidget(), NULL);
  
    mgr->append(label);
  }
  
  mgr->show();

  int width, height;
  Dimension scrollBarWidth;

  ((TiburonApp *)theApplication)->rovMainWindow()->viewPortSize(&width, 
								&height);

  _scrolledWindow = 
    XtVaCreateWidget("scrolledWindow", xmScrolledWindowWidgetClass,
		     _baseWidget,
		     XmNscrollingPolicy, XmAUTOMATIC,
		     XmNscrollBarDisplayPolicy, XmAS_NEEDED,
		     XmNtopAttachment, XmATTACH_WIDGET,
		     XmNtopWidget, mgr->baseWidget(),
		     XmNleftAttachment, XmATTACH_FORM,
		     XmNrightAttachment, XmATTACH_FORM,  
		     XmNheight, height - 200,
		     NULL);

  Widget scrollBar;
  
  XtVaGetValues(_scrolledWindow, XmNverticalScrollBar, &scrollBar, NULL);

  XtVaGetValues(scrollBar, XmNwidth, &scrollBarWidth, NULL);

  // Set width of header
  XtVaSetValues(mgr->baseWidget(), XmNwidth, width - scrollBarWidth, NULL);
  
  _table = XtVaCreateWidget("table", xmRowColumnWidgetClass, 
			    _scrolledWindow,
			    XmNwidth, width - scrollBarWidth,
			    XmNresizeWidth, False,
			    NULL);
  
  XtManageChild(_table);
  XtManageChild(_scrolledWindow);
  
  Widget saveButton = 
    XtVaCreateManagedWidget("saveButton", xmPushButtonWidgetClass, _baseWidget,
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, _scrolledWindow,
			    NULL);
  
  XtAddCallback(saveButton, XmNactivateCallback,
		&VspPage::saveCallback, (XtPointer )this);
  

  checkForNewEntries();
}


VspPage::~VspPage()
{
}


int VspPage::checkForNewEntries()
{
  Boolean debug = False;
  dprintf(stderr, "VspPage::checkForNewEntries()\n");
  
  int newEntries = 0;
  
  char pattern[MaxDmNameLen];
  sprintf(pattern, "*VSP*.%s", VSP_BAUD_DM);
  
  DM_Item dmItem;
  DM_Item prevItem = NO_ITEM;
  DM_Num nItems;
  VspEntry *entry;

  while ((dmItem = dm_search(pattern, prevItem, &nItems)) != NO_ITEM)
  {
    DmItemSts itemStatus;
    
    dm_item_status(dmItem, &itemStatus);
    dprintf(stderr, "VspPage::checkForNewEntries() - item name \"%s\"\n",
	    itemStatus.is_name);
    
    char *suffix;
    char dmPrefix[MaxDmNameLen];
    const char *entryName;
    
    Boolean parseError = False;

    if ((suffix = strrchr(itemStatus.is_name, '.')) == NULL)
      parseError = True;
    else
    {
      suffix++;
      strncpy(dmPrefix, itemStatus.is_name, suffix - itemStatus.is_name);
      dmPrefix[suffix-itemStatus.is_name] = '\0';
      VehicleComponent *parent = 
	((TiburonApp *)theApplication)->vehicleConfig->vehicleBase;

      if ((entryName = getEntryName(dmPrefix, parent)) == NULL)
	entryName = dmPrefix;
    }
    
    if (parseError)
    {
      fprintf(stderr, 
	      "VspPage::checkForNewEntries() - Couldn't parse prefix from "
	      "\"%s\"\n", 
	      itemStatus.is_name);

      dm_item_status_free(&itemStatus);
      prevItem = dmItem;
      continue;
    }

    // Determine if we already have this item
    Boolean found = False;
    for (int i = 0; i < _entries.size(); i++)
    {
      _entries.get(i, &entry);
      if (!strcmp(entry->name(), entryName))
      {
	found = True;
	break;
      }
    }

    if (!found)
    {
      // Item not in table yet, so add it
      dprintf(stderr, 
	      "VspPage::checkForNewEntries() - found new entry \"%s\"\n",
	      entryName);

      entry = new VspEntry(entryName, _table, dmPrefix, this);
      entry->show();
      XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass, _table,
			      NULL);
      
      _entries.add(&entry);
      newEntries++;
    }

    dm_item_status_free(&itemStatus);
    prevItem = dmItem;
  }

  dprintf(stderr, "VspPage::checkForNewEntries(); found %d new entries\n",
	  newEntries);
  
  return newEntries;
}


const char *VspPage::getEntryName(const char *dmPrefix, 
				  VehicleComponent *parent)
{
  const char *ename;
  VehicleComponent **child;
  SListIter<VehicleComponent *> children(parent->childList);
  
  while (child = children.next())
  {
    if ((*child)->type() == VehicleComponent::IbcType || 
	(*child)->type() == VehicleComponent::DconType)
    {
      Micro *micro = (Micro *)(*child);
      
      if (!strncmp(micro->dmPrefix(), dmPrefix, strlen(micro->dmPrefix())))
	return micro->name();
    }
    if ((ename = getEntryName(dmPrefix, *child)) != NULL)
      return ename;
  }

  return NULL;
}


void VspPage::createConfigDialog(const VspEntry *vspEntry)
{
  if (_configDialog) delete _configDialog;
  
  _configDialog = new VspConfigDialog("vspConfigDialog", vspEntry);
  _configDialog->setTitle("Configure VSP");
  _configDialog->post(NULL, 
		      &VspConfigDialog::okayCallback,
		      NULL, 
		      &VspConfigDialog::okayCallback,
		      (XtPointer )_configDialog);
}


void VspPage::show()
{
  Boolean debug = False;
  dprintf(stderr, "VspPage::show()\n");
  
  VkComponent::show();
  startTimer();
}


void VspPage::hide()
{
  Boolean debug = False;
  dprintf(stderr, "VspPage::hide()\n");
  
  VkComponent::hide();
  stopTimer();
}


void VspPage::startTimer()
{
  if (!_timer)
  {
    _timer = 
      XtAppAddTimeOut(theApplication->appContext(), 5000,
		      &VspPage::timerCallback, (XtPointer )this);  
  }
}



void VspPage::stopTimer()
{
  if (_timer)
  {
    XtRemoveTimeOut(_timer);
    _timer = NULL;
  }
}


int VspPage::valueToIndex(MnemonicValue *mnemonicValue, int value)
{
  MnemonicValue *ptr;
  int index;
  
  for (index = 0, ptr = mnemonicValue; 
       ptr->mnemonic != NULL; 
       ptr++, index++)
  {
    if (ptr->value == value)
      return index;
  }

  return -1;
}


void VspPage::saveCallback(Widget w,
			   XtPointer clientData,
			   XtPointer callData)
{
  VspPage *obj = (VspPage *)clientData;
  
  theInfoDialog->postAndWait("Configuration backup not yet implemented");
}



Void VspPage::timerCallback(XtPointer clientData, XtIntervalId *id)
{
  Boolean debug = False;
  dprintf(stderr, "*** VspPage::timerCallback()\n");
  
  VspPage *obj = (VspPage *)clientData;

  obj->checkForNewEntries();
  obj->_timer = NULL;
  obj->startTimer();
}


