static char PeriodicHandler_id[] = "$Header: PeriodicHandler.cc,v 1.7 97/10/03 09:31:56 oreilly Exp $";


/*
$Log:	PeriodicHandler.cc,v $
Revision 1.7  97/10/03  09:31:56  09:31:56  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.6  97/04/30  19:33:10  19:33:10  oreilly (Thomas C. O'Reilly)
Check that DmGuiObject is in list when unregistering it

Revision 1.5  97/03/20  12:30:27  12:30:27  oreilly (Thomas C. O'Reilly)
..

Revision 1.4  96/10/28  09:12:33  09:12:33  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.3  96/07/22  10:42:08  10:42:08  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <values.h>
#include <Vk/VkApp.h>
#include <Vk/VkErrorDialog.h>
#include "PeriodicHandler.h"


RegisteredPeriod::RegisteredPeriod(int interval)
{
  _interval = interval;
}


PeriodicHandler::PeriodicHandler() 
{
  _accumulated = 0;
  _running = FALSE;
}


int PeriodicHandler::registerObj(DmGuiObject *dmGuiObject, 
				 int interval)
{
  MBool debug = FALSE;
  MBool found = FALSE;
  RegisteredPeriod **period;
  RegisteredPeriod *newPeriod;
  SListIter <RegisteredPeriod *> periods(_periodList);
  
  periods.reset();  

  while ((period = periods()) != NULL)
  {
    if ((*period)->_interval == interval)
    {
      /* interval has been registered */
      found = TRUE;
      /* Add dmGuiObject to period's list */
      (*period)->addDmGuiObject(dmGuiObject);
    }
    else
    {
      /* If dmGuiObject is in another interval's list, remove 
	 it from that list */
      (*period)->removeDmGuiObject(dmGuiObject);
      if ((*period)->length() == 0)
	periods.remove();
    }
  }
  
  if (!found)
  {
    dprintf(stderr, "Register period %d\n", interval);

    newPeriod = new RegisteredPeriod(interval);
    /* Add dmGuiObject to period's list */
    newPeriod->addDmGuiObject(dmGuiObject);
    /* Add new interval to registered items */
    _periodList.append(newPeriod);
  }

  if (_running)
  {
    dprintf(stderr, "stop()\n");
    stop();
    dprintf(stderr, "start()\n");
    start();
  }
  
  return 0;
}


int PeriodicHandler::unregisterObj(DmGuiObject *guiObj)
{
  // Go through all registered periods, make sure guiObj is removed
  RegisteredPeriod **period;
  SListIter<RegisteredPeriod *> periods(_periodList);
 
  periods.reset();
  MBool found = FALSE;
  
  while ((period = periods()) != NULL)
  {
    if ((*period)->removeDmGuiObject(guiObj) == 0)
      found = TRUE;
    
    if ((*period)->length() == 0)
      periods.remove();
  }

  if (_running)
  {
    stop();
    start();
  }

  if (!found)
    return -1;
  else
    return 0;
}


int PeriodicHandler::timerInterval()
{
  MBool debug = FALSE;
  RegisteredPeriod **period;

  SListIter<RegisteredPeriod *> periods(_periodList);
  periods.reset();
  int minInterval = MAXINT;
  _maxInterval = 0;

  while (period = periods())
  {
    if ((*period)->_interval < minInterval)
      minInterval = (*period)->_interval;

    if ((*period)->_interval > _maxInterval)
      _maxInterval = (*period)->_interval;
  }

  if (minInterval == MAXINT)
    return MAXINT;
  
  // Find greatest integer by which all intervals are divisible
  _timerInterval = 1; 
  for (int gcd = 2; gcd <= minInterval; gcd++)
  {
    periods.reset();
    MBool allDivisible = TRUE;
    while (period = periods.next())
    {
      if ((*period)->_interval % gcd)
      {
	allDivisible = FALSE;
	break;
      }
    }
    if (allDivisible)
      _timerInterval = gcd;
  }

  dprintf(stderr, "PeriodicHandler::timerInterval() interval=%d\n",
	  _timerInterval);
  
  return _timerInterval;
}


void PeriodicHandler::timerCallback(XtPointer clientData,
				    XtIntervalId *id)
{
  MBool debug = FALSE;

  dprintf(stderr, "PeriodicHandler::timerCallback()\n");

  PeriodicHandler *obj = (PeriodicHandler *)clientData;
  
  // Re-start timer
  obj->restart();  

  // Update DmGuiObjects at appropriate frequency
  obj->handleTimeout();
}


void PeriodicHandler::handleTimeout()
{
  MBool debug = False;
  char errorBuf[errorMsgSize];
  
  // Accumulate time
  _accumulated += _timerInterval;

  dprintf(stderr, "PeriodicHandler::handleTimeout()\n");
    
  SListIter<RegisteredPeriod *> periods(_periodList);

  periods.reset();
  RegisteredPeriod **period;  
  while ((period = periods()) != NULL) 
  {
    if (!(_accumulated % (*period)->_interval))
    {
      if ((*period)->_interval == 1000)
	dprintf(stderr, 
		"_accumulated=%d: interval 1000 expired\n", _accumulated);
	
      // Update DmGuiObjects associated with this period
      DmGuiObject **dmGuiObject;
      SListIter<DmGuiObject *> objects((*period)->_objectList);
      
      objects.reset();
      while (dmGuiObject = objects())
      {
	if ((*dmGuiObject)->consumeEnabled())
	{
	if ((*period)->_interval == 1000)
	  dprintf(stderr, "Call %s->updateGui()\n", (*dmGuiObject)->name());

	  (*dmGuiObject)->updateGui();
	  if ((*dmGuiObject)->error())
	  {
	    sprintf(errorBuf,
		    "PeriodicHandler::handleTimeout() - error from "
		    "updateGui() function of \"%s\"\n", 
		    (*dmGuiObject)->name());

//	    theErrorDialog->post(errorBuf);
	    fprintf(stderr, "%s\n", errorBuf);
	    (*dmGuiObject)->prtErrorMsg();
	    (*dmGuiObject)->clearError();
	  }
	}
      }
    }
  }
  if (_accumulated > _maxInterval)
    _accumulated = 0;
}


