#pragma once
#include "common.hpp"
#include "hooks.hpp"
#include "pool.hpp"


/** Periodically call some handler. Gets called from @see Poll */
class Periodic {
    private:
        static Periodic* inst;
        Periodic() { assert(!inst); inst = this; }

        typedef bool (*handler_t)(); // TODO: move timeout/wakeup out of poll into here?
        typedef struct { handler_t h; unsigned i; time_t t; } periodic_t;
        std::vector<periodic_t> periodic;

    public:
        static INLINE Periodic* getInst() { return inst ?: new Periodic(); }
        static INLINE bool hasInst() { return inst != NULL; }
        INLINE ~Periodic() { assert(inst == this); inst = NULL; }

        void add(handler_t, unsigned); ///< for a few handlers (very inperformant for many handlers) that should be called every specific interval
        bool del(handler_t); ///< also costly operation for removing a handler again
        void run();
};


/** From a thread, enqueue some handler to be called synchronously. Gets called from @see Poll */
class WakeUp {
    public:
        typedef void (*handler_t)(void*);

    private:
        static WakeUp* inst;
        WakeUp(): wakeups(NULL), lock(0) { assert(!inst); inst = this; }

        typedef struct wakeup_s { handler_t h; void* ctx; struct wakeup_s* next; } wakeup_t;
        TPool<wakeup_t> pool;
        wakeup_t* wakeups;
        atomic_t lock;

    public:
        static INLINE WakeUp* getInst() { return inst ?: new WakeUp(); }
        INLINE ~WakeUp() { assert(inst == this); run(); inst = NULL; }

        void add(handler_t, void*); ///< threadsafe
        void run();
};


/** Gets called everytime from @see Poll */
class Poller {
    public:
        typedef bool (*handler_t)(void*); ///< gets called as long as it returns true

    private:
        static Poller* inst;
        Poller(): pollers(NULL) { assert(!inst); inst = this; }

        typedef struct poller_s { handler_t h; void* ctx; struct poller_s* next; } poller_t;
        TPool<poller_t> pool;
        poller_t* pollers;

    public:
        static INLINE Poller* getInst() { return inst ?: new Poller(); }
        INLINE ~Poller();

        void add(handler_t, void*);
        bool del(handler_t, void*); ///< costly operation, must not be called when already running
        void run();
};