#ifndef _PROTO_TIMER
#define _PROTO_TIMER
#include "protoDebug.h"
#include "protoDefs.h"
#include "protoTime.h"
#include "protoTree.h"
#include <math.h>
#define _SORTED_TIMERS 1
class ProtoTimer
#ifdef _SORTED_TIMERS
: public ProtoSortedTree::Item
#endif {
friend class ProtoTimerMgr;
public:
ProtoTimer();
~ProtoTimer();
template <class LTYPE>
bool SetListener(LTYPE* theListener, void(LTYPE::*timeoutHandler)(ProtoTimer&))
{
if (NULL != listener) delete listener;
listener = theListener ? new LISTENER_TYPE<LTYPE>(theListener, timeoutHandler) : NULL;
return (NULL == listener) ? (NULL != theListener) : true;
}
template <class LTYPE>
bool SetListener(LTYPE* theListener, bool(LTYPE::*timeoutHandler)(ProtoTimer&))
{
if (NULL != listener) delete listener;
listener = theListener ? new OLD_LISTENER_TYPE<LTYPE>(theListener, timeoutHandler) : NULL;
return (NULL == listener) ? (NULL != theListener) : true;
}
void SetInterval(double theInterval)
{interval = (theInterval >= 1.0e-06) ? theInterval : ((theInterval > 0.0) ? 1.0e-06 : 0.0);}
double GetInterval() const {return interval;}
void SetRepeat(int numRepeat)
{repeat = numRepeat;}
int GetRepeat() const
{return repeat;}
void ResetRepeat()
{repeat_count = repeat;}
void DecrementRepeatCount()
{ if (repeat_count > 0) repeat_count--; }
int GetRepeatCount() {return repeat_count;}
void SetRepeatCount(int repeatCount)
{repeat_count = repeatCount;}
bool IsActive() const {return (NULL != mgr);}
double GetTimeRemaining() const;
const ProtoTime GetTimeout() const {return timeout;}
void Reset()
{
ResetRepeat();
if (IsActive()) Reschedule();
}
bool Reschedule();
void Scale(double factor);
void Deactivate();
void SetUserData(const void* userData) {user_data = userData;}
const void* GetUserData() {return user_data;}
enum Command {INSTALL, MODIFY, REMOVE};
#ifdef _SORTED_TIMERS
void UpdateKey()
{timeout_key.SetValue(timeout);}
void InvalidateKey()
{timeout_key.Invalidate();}
bool KeyIsValid() const
{return timeout_key.IsValid();}
const char* GetKey() const
{return timeout_key.GetKey();}
unsigned int GetKeysize() const
{return timeout_key.GetKeysize();}
#endif
private:
void DoTimeout()
{if (NULL != listener) listener->on_timeout(*this);}
class Listener
{
public:
virtual ~Listener() {}
virtual void on_timeout(ProtoTimer& theTimer) = 0;
};
template <class LTYPE>
class LISTENER_TYPE : public Listener
{
public:
LISTENER_TYPE(LTYPE* theListener, void(LTYPE::*timeoutHandler)(ProtoTimer&))
: listener(theListener), timeout_handler(timeoutHandler) {}
void on_timeout(ProtoTimer& theTimer)
{(listener->*timeout_handler)(theTimer);}
Listener* duplicate()
{return (static_cast<Listener*>(new LISTENER_TYPE<LTYPE>(listener, timeout_handler)));}
private:
LTYPE* listener;
void (LTYPE::*timeout_handler)(ProtoTimer&);
};
class OldListener : public Listener
{
public:
virtual ~OldListener() {}
void on_timeout(ProtoTimer& theTimer)
{old_on_timeout(theTimer);}
private:
virtual bool old_on_timeout(ProtoTimer& theTimer) = 0;
};
template <class LTYPE>
class OLD_LISTENER_TYPE : public OldListener
{
public:
OLD_LISTENER_TYPE(LTYPE* theListener, bool(LTYPE::*timeoutHandler)(ProtoTimer&))
: listener(theListener), timeout_handler(timeoutHandler) {}
bool old_on_timeout(ProtoTimer& theTimer)
{return (listener->*timeout_handler)(theTimer);}
OldListener* duplicate()
{return (static_cast<OldListener*>(new OLD_LISTENER_TYPE<LTYPE>(listener, timeout_handler)));}
private:
LTYPE* listener;
bool (LTYPE::*timeout_handler)(ProtoTimer&);
};
Listener* listener;
double interval;
int repeat;
int repeat_count;
const void* user_data;
ProtoTime timeout;
bool is_precise;
class ProtoTimerMgr* mgr;
#ifdef _SORTED_TIMERS
ProtoTime::Key timeout_key;
#else
ProtoTimer* prev;
ProtoTimer* next;
#endif };
#ifdef _SORTED_TIMERS
class ProtoTimerList : public ProtoListTemplate<ProtoTimer> {};
class ProtoTimerTable : public ProtoSortedTreeTemplate<ProtoTimer> {};
#endif
class ProtoTimerMgr
{
friend class ProtoTimer;
public:
ProtoTimerMgr();
virtual ~ProtoTimerMgr();
virtual void ActivateTimer(ProtoTimer& theTimer);
virtual void DeactivateTimer(ProtoTimer& theTimer);
bool IsActive() const
{return (NULL != GetShortHead());}
double GetTimeRemaining() const
{
ProtoTimer* next = GetShortHead();
return ((NULL != next) ? next->GetTimeRemaining() : -1.0);
}
void OnSystemTimeout();
void DoSystemTimeout()
{
bool updateStatus = update_pending;
update_pending = true;
OnSystemTimeout();
update_pending = updateStatus;
}
virtual void GetSystemTime(struct timeval& currentTime);
#ifdef _SORTED_TIMERS
ProtoTimerTable& GetTimerTable() {return timer_table;}
ProtoTimerList& GetTimerList() {return timer_list;}
ProtoTimerTable& GetLongTable() {return long_timer_table;}
#endif
protected:
virtual bool UpdateSystemTimer(ProtoTimer::Command command,
double delay) = 0;
private:
void ReactivateTimer(ProtoTimer& theTimer, const ProtoTime& now);
void InsertLongTimer(ProtoTimer& theTimer);
bool InsertLongTimerReverse(ProtoTimer& theTimer);
void RemoveLongTimer(ProtoTimer& theTimer);
void InsertShortTimer(ProtoTimer& theTimer);
bool InsertShortTimerReverse(ProtoTimer& theTimer);
void RemoveShortTimer(ProtoTimer& theTimer);
void Update();
#ifdef _SORTED_TIMERS
ProtoTimer* GetShortHead() const
{
ProtoTimer* next = timer_list.GetHead();
return (NULL != next) ? next : timer_table.GetHead();
}
ProtoTimer* GetLongHead() const {return long_timer_table.GetHead();}
#else
ProtoTimer* GetShortHead() const {return short_head;}
ProtoTimer* GetLongHead() const {return long_head;}
#endif
bool GetNextTimeout(ProtoTime& nextTimeout) const
{
ProtoTimer* next = GetShortHead();
if (NULL != next)
{
nextTimeout = next->timeout;
return true;
}
else
{
return false;
}
}
void GetPulseTime(ProtoTime& pulseTime) const
{
pulseTime = pulse_mark;
pulseTime += (1.0 - pulse_timer.GetTimeRemaining());
}
bool OnPulseTimeout(ProtoTimer& theTimer);
static const double PRECISION_TIME_THRESHOLD;
void GetCurrentSystemTime(struct timeval& currentTime)
{
#if (defined(SIMULATE) && defined(NS2))
GetSystemTime(currentTime);
#else
ProtoSystemTime(currentTime);
#endif }
void GetCurrentProtoTime(ProtoTime& currentTime)
{
#if (defined(SIMULATE) && defined(NS2))
GetSystemTime(currentTime.AccessTimeVal());
#else
currentTime.GetCurrentTime();
#endif }
bool update_pending;
bool timeout_scheduled;
ProtoTime scheduled_timeout;
ProtoTimer pulse_timer; ProtoTime pulse_mark;
#ifdef _SORTED_TIMERS
unsigned int timer_list_count;
ProtoTimerList timer_list;
ProtoTimerTable timer_table;
ProtoTimerTable long_timer_table;
#else
ProtoTimer* long_head;
ProtoTimer* long_tail;
ProtoTimer* short_head;
ProtoTimer* short_tail;
#endif ProtoTimer* invoked_timer; };
#endif