static char DmMonitor_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/DmMonitor.cc,v 1.3 1997/08/12 14:39:58 oreilly Exp $";


/*
$Log: DmMonitor.cc,v $
Revision 1.3  1997/08/12 14:39:58  oreilly
*** empty log message ***

Revision 1.2  97/03/20  12:29:12  12:29:12  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.1  96/07/22  10:41:56  10:41:56  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "DmMonitor.h"
#include "DmErrno.h"

#define dprintf if (debug) fprintf

MonitoredGroup::MonitoredGroup()
{
  for (int slot = 0; slot < MAX_GROUP_SIZE; slot++)
  {
    items[slot].handle = EmptySlot;
  }
}


DmMonitor::DmMonitor(SEM_ID wakeupSem, int writeFd) 
{
  _wakeupSem = wakeupSem;
  _writeFd = writeFd;
  
  newGroup();
  _totalItems = 0;
}


DmMonitor::~DmMonitor() 
{
  int i;
  MonitoredGroup *group;
  
  for (i = 0; i < _groups.size(); i++)
  {
    _groups.get(i, &group);
    dm_delete_group(group->id);
  }
}


MonitoredGroup *DmMonitor::newGroup()
{
  MBool debug = FALSE;
  MonitoredGroup *group = new MonitoredGroup(); 
  group->id = dm_create_group();
  dprintf(stderr, "DmMonitor::addGroup() - id = %d\n", group->id);
  group->nItems = 0;
  _groups.add(&group);
  return group;
}


MonitoredGroup *DmMonitor::availableGroup()
{
  MonitoredGroup *group;
  
  for (int i = 0; i < _groups.size(); i++)
  {
    _groups.get(i, &group);
    if (group->nItems < MAX_GROUP_SIZE)
      return group;
  }

  // No empty slots. Need to create a new group  
  return newGroup();
}


int DmMonitor::handleRequest(RequestMessage *request)
{
  if (request->cmd == AddItem)
    return addItem(request);
  else if (request->cmd == RemoveItem)
    return removeItem(request);
  else
  {
    fprintf(stderr, "DmMonitor::handleRequest() - unknown command %d\n",
	    request->cmd);
    return -1;
  }
}


int DmMonitor::addItem(RequestMessage *request)
{
  DWord idBit;
  MBool debug = FALSE;
  dprintf(stderr, "DmMonitor::addItem(): item \"%s\"\n", request->itemName);

  Errno err;
  MBool error = FALSE;
  DM_Item handle;
  
  if ((handle = dm_lookup(request->itemName, request->arrayIndex)) 
      == NO_ITEM)
  {
    fprintf(stderr, "DmMonitor::addItem() - dm_lookup(%s, %d) failed\n",
	    request->itemName, request->arrayIndex);

    return -1;
  }


  char buf[512];
  char buf2[512];
  if ((err = dm_start_consumer(handle, request->period, _wakeupSem)) 
      != SUCCESS && err != EDM_TOOFAST && err != EDM_PERIOD)
  {
    sprintDmError(err, "DmMonitor::addItem() - dm_start_consumer()", buf);
    fprintf(stderr, buf);
    error = TRUE;
  }

  MonitoredGroup *group = availableGroup();

  if ((err = dm_group_add_item(group->id, handle, &idBit)) != SUCCESS)
  {
    sprintf(buf2, "DmMonitor::addItem() - dm_group_add_item(), group->id=%d, "
		  "handle=0x%x", group->id, handle);

    sprintDmError(err, buf2, buf);
    
    fprintf(stderr, "%s\n", buf);
    error = TRUE;
  }

  int slot;
  
  // Determine slot that was just filled
  for (slot = 0; slot < MAX_GROUP_SIZE; slot++)
  {
    if (idBit & (01 << slot))
      break;
  }
  dprintf(stderr, "Filled slot %d\n", slot);
  
  MonitoredGroupItem *item = &group->items[slot];
  item->handle = handle; 
  item->guiListPtr = request->guiListPtr;

  dprintf(stderr, "addItem(); item #%d, handle=%x, guiListPtr=%x\n", 
	  group->nItems, item->handle, item->guiListPtr);
  
  group->nItems++;
  _totalItems++;

  if (error)
    return -1;

  return 0;
}


int DmMonitor::removeItem(RequestMessage *request)
{
  MBool debug = FALSE;
  DM_Item handle;
  
  dprintf(stderr, "DmMonitor::removeItem(): item \"%s\"\n", request->itemName);

  if ((handle = dm_lookup(request->itemName, request->arrayIndex)) 
      == NO_ITEM)
  {
    fprintf(stderr, "DmMonitor::addItem() - dm_lookup(%s, %d) failed\n",
	    request->itemName, request->arrayIndex);

    return -1;
  }
  
  MonitoredGroup *group;
  Errno err;
  char buf[512];
  MBool error = FALSE;;
  MBool found = FALSE;
  // Search through groups for specified item
  for (int i = 0; i < _groups.size() && !found; i++)
  {
    _groups.get(i, &group);
    for (int slot = 0; slot < MAX_GROUP_SIZE; slot++)
    {
      if (group->items[slot].handle == handle)
      {
	dprintf(stderr, "Removing item \"%s\", group #%d, index %d\n",
		request->itemName, i, slot);
      
	if ((err = dm_group_delete_item(group->id, handle)) != SUCCESS)
	{
	  sprintDmError(err, 
			"DmMonitor::removeItem() - dm_group_delete_item()", 
			buf);

	  fprintf(stderr, "%s\n", buf);
	  fprintf(stderr, "group->id=%d, handle=%d\n",
		  group->id, handle);
	  
	  error = TRUE;
	}

        // 1 less item in group now
	group->nItems--;
	
	if ((err = dm_stop_consumer(handle)) != SUCCESS)
	{
	  sprintDmError(err, "DmMonitor::removeItem() - dm_stop_consumer()", 
			buf);

	  fprintf(stderr, "%s\n", buf);
	  fprintf(stderr, "handle=%d\n", handle);
	  error = TRUE;
	}

	group->items[slot].handle = EmptySlot;	
	found = TRUE;
	break;
      }
    }
  }
  if (!found)
  {
    fprintf(stderr, 
	    "DmMonitor::removeItem() - couldn't find item \"%s\"\n",
	    request->itemName);

    error = TRUE;
  }    
  if (error)
    return -1;
  
  return 0;
}


MBool DmMonitor::newData()
{
  int i;
  MonitoredGroup *group;
  
  for (i = 0; i < _groups.size(); i++)
  {
    _groups.get(i, &group);
    if (dm_get_group_changes(group->id))
      return TRUE;
  }
  // No new data
  return FALSE;
}

int DmMonitor::handleNewData()    
{
  int i;
  MonitoredGroup *group;
  MBool debug = FALSE;
  int nBytes;
  int nFound = 0;
  
  for (i = 0; i < _groups.size(); i++)
  {
    _groups.get(i, &group);
    DWord changedItemMap;
    if (changedItemMap = dm_get_group_changes(group->id))
    {
      dprintf(stderr, "handleNewData() - New data detected\n");
      for (int item = 0; item < MAX_GROUP_SIZE; item++)
      {
	if ((01 << item) & changedItemMap)
	{
	  /* Data is ready; notify application */
	  if (debug)
	  {
	    DmItemSts status;
	    dm_item_status(group->items[item].handle, &status);
	    
	    dprintf(stderr, 
		    "handleNewData() - Item #%d, handle=%x, name=\"%s\"\n", 
		    item, group->items[item].handle, status.is_name);

	    dm_item_status_free(&status);
	  }
	  
	  if ((nBytes = write(_writeFd, &group->items[item], 
			      sizeof(MonitoredGroupItem))) 
	      != sizeof(MonitoredGroupItem))
	  {
	    perror("DmMonitor::handleNewData() - write()");
	    return -1;
	  }
	  nFound++;
	}
      }
    }
  }
  if (nFound)
    dprintf(stderr, "Detected and handled %d changed items\n", nFound);

  return 0;
}


int DmMonitor::nItems()
{
  return _totalItems;
}

