// $Id: Timer.cc,v 1.15 2002/10/11 02:04:40 leres Exp $
//
// Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "config.h"

#include "util.h"
#include "Timer.h"

void Timer::Cancel()
	{
	active = 0;
	}

TimerMgr::~TimerMgr()
	{
	}

int TimerMgr::Advance(double arg_t, int max_expire)
	{
	t = arg_t;
	num_expired = 0;
	return DoAdvance(t, max_expire);
	}


PQ_TimerMgr::PQ_TimerMgr() : TimerMgr()
	{
	q = new PriorityQueue;
	}

PQ_TimerMgr::~PQ_TimerMgr()
	{
	delete q;
	}

void PQ_TimerMgr::Add(Timer* timer)
	{
	// Add the timer even if it's already expired - that way, if
	// multiple already-added timers are added, they'll still
	// execute in sorted order.
	if ( ! q->Add(timer) )
		internal_error("out of memory");
	}

void PQ_TimerMgr::Expire()
	{
	Timer* timer;
	while ( (timer = Remove()) )
		{
		timer->Dispatch(t, 1);
		delete timer;
		}
	}

int PQ_TimerMgr::DoAdvance(double new_t, int max_expire)
	{
	Timer* timer = Top();
	for ( num_expired = 0; (num_expired < max_expire || max_expire == 0) &&
		     timer && timer->Time() <= new_t; ++num_expired )
		{
		timer->Dispatch(new_t, 0);
		delete Remove();
		timer = Top();
		}

	return num_expired;
	}


CQ_TimerMgr::CQ_TimerMgr() : TimerMgr()
	{
	cq = cq_init(60.0, 1.0);
	if ( ! cq )
		internal_error("could not initialize calendar queue");
	}

CQ_TimerMgr::~CQ_TimerMgr()
	{
	cq_destroy(cq);
	}

void CQ_TimerMgr::Add(Timer* timer)
	{
	// Add the timer even if it's already expired - that way, if
	// multiple already-added timers are added, they'll still
	// execute in sorted order.
	if ( cq_enqueue(cq, timer->Time(), timer) < 0 )
		internal_error("problem queueing timer");
	}

void CQ_TimerMgr::Expire()
	{
	double huge_t = 1e20;	// larger than any Unix timestamp
	for ( Timer* timer = (Timer*) cq_dequeue(cq, huge_t);
	      timer; timer = (Timer*) cq_dequeue(cq, huge_t) )
		{
		timer->Dispatch(huge_t, 1);
		delete timer;
		}
	}

int CQ_TimerMgr::DoAdvance(double new_t, int max_expire)
	{
	Timer* timer;
	while ( (num_expired < max_expire || max_expire == 0) &&
		(timer = (Timer*) cq_dequeue(cq, new_t)) )
		{
		timer->Dispatch(new_t, 0);
		delete timer;
		++num_expired;
		}

	return num_expired;
	}
