+//////////////////////////////////////////////////////////////////////////
+
+
+class TimerObj : public SGReferenced
+{
+public:
+ TimerObj(FGNasalSys* sys, naRef f, naRef self, double interval) :
+ _sys(sys),
+ _func(f),
+ _self(self),
+ _isRunning(false),
+ _interval(interval),
+ _singleShot(false)
+ {
+ char nm[128];
+ snprintf(nm, 128, "nasal-timer-%p", this);
+ _name = nm;
+ _gcRoot = sys->gcSave(f);
+ _gcSelf = sys->gcSave(self);
+ }
+
+ virtual ~TimerObj()
+ {
+ stop();
+ _sys->gcRelease(_gcRoot);
+ _sys->gcRelease(_gcSelf);
+ }
+
+ bool isRunning() const { return _isRunning; }
+
+ void stop()
+ {
+ if (_isRunning) {
+ globals->get_event_mgr()->removeTask(_name);
+ _isRunning = false;
+ }
+ }
+
+ void start()
+ {
+ if (_isRunning) {
+ return;
+ }
+
+ _isRunning = true;
+ if (_singleShot) {
+ globals->get_event_mgr()->addEvent(_name, this, &TimerObj::invoke, _interval);
+ } else {
+ globals->get_event_mgr()->addTask(_name, this, &TimerObj::invoke,
+ _interval, _interval /* delay */);
+ }
+ }
+
+ // stop and then start -
+ void restart(double newInterval)
+ {
+ _interval = newInterval;
+ stop();
+ start();
+ }
+
+ void invoke()
+ {
+ if( _singleShot )
+ // Callback may restart the timer, so update status before callback is
+ // called (Prevent warnings of deleting not existing tasks from the
+ // event manager).
+ _isRunning = false;
+
+ naRef *args = NULL;
+ _sys->callMethod(_func, _self, 0, args, naNil() /* locals */);
+ }
+
+ void setSingleShot(bool aSingleShot)
+ {
+ _singleShot = aSingleShot;
+ }
+
+ bool isSingleShot() const
+ { return _singleShot; }
+private:
+ std::string _name;
+ FGNasalSys* _sys;
+ naRef _func, _self;
+ int _gcRoot, _gcSelf;
+ bool _isRunning;
+ double _interval;
+ bool _singleShot;
+};
+
+typedef SGSharedPtr<TimerObj> TimerObjRef;
+typedef nasal::Ghost<TimerObjRef> NasalTimerObj;
+
+///////////////////////////////////////////////////////////////////////////