// $Id: Timer.h,v 1.14 2002/10/11 02:20:15 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.

#ifndef timer_h
#define timer_h

#include "PriorityQueue.h"

extern "C" {
#include "cq.h"
}

class Timer : public PQ_Element {
public:
	Timer(double t) : PQ_Element(t)		{ active = 1; }

	// t gives the dispatch time.  is_expire is true if the
	// timer is being dispatched because we're expiring all
	// pending timers.  The method should check "active" to
	// see if the timer has been canceled.
	virtual void Dispatch(double t, int is_expire) = 0;

	// Default version simply clears "active".
	virtual void Cancel();

protected:
	int active;
};

class TimerMgr {
public:
	virtual ~TimerMgr();

	virtual void Add(Timer* timer) = 0;

	// Advance the clock to time t, expiring at most max_expire timers.
	// Returns number of timers expired.
	int Advance(double t, int max_expire);

	// Returns the number of timers expired (so far) during the current
	// or most recent advance.
	int NumExpiredDuringCurrentAdvance()	{ return num_expired; }

	// Expire all timers.
	virtual void Expire() = 0;

	void Cancel(Timer* timer)	{ timer->Cancel(); }

	double Time() const		{ return t; }

	virtual int Size() const = 0;
	virtual int PeakSize() const = 0;

protected:
	TimerMgr()	{ t = 0.0; num_expired = 0; }

	virtual int DoAdvance(double t, int max_expire) = 0;

	double t;
	int num_expired;
};

class PQ_TimerMgr : public TimerMgr {
public:
	PQ_TimerMgr();
	~PQ_TimerMgr();

	void Add(Timer* timer);
	void Expire();

	int Size() const	{ return q->Size(); }
	int PeakSize() const	{ return q->PeakSize(); }

protected:
	int DoAdvance(double t, int max_expire);

	Timer* Remove()			{ return (Timer*) q->Remove(); }
	Timer* Top()			{ return (Timer*) q->Top(); }

	PriorityQueue* q;
};

class CQ_TimerMgr : public TimerMgr {
public:
	CQ_TimerMgr();
	~CQ_TimerMgr();

	void Add(Timer* timer);
	void Expire();

	int Size() const	{ return cq_size(cq); }
	int PeakSize() const	{ return cq_max_size(cq); }

protected:
	int DoAdvance(double t, int max_expire);

	struct cq_handle *cq;
};

extern TimerMgr* timer_mgr;

#endif
