#include "callout.hpp"


HOOK(POST_IO, HOOK_PRIO_MID) {
    delete Periodic::getInst();
    delete WakeUp::getInst();
    delete Poller::getInst();
}


//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//


Periodic* Periodic::inst = NULL;


void Periodic::run() {
    for (std::vector<periodic_t>::iterator it = periodic.begin(); it != periodic.end();) {
        log(io, "periodic handler %p in: %ld", it->h, it->t-NOW);
        if (unlikely(it->t <= NOW)) {
            if (it->h()) {
                it->t = NOW + it->i;
                ++it;
            } else {
                it = periodic.erase(it);
            }
        } else {
            ++it;
        }
    }
}


void Periodic::add(handler_t h, unsigned i) {
    (void)del(h);
    periodic.push_back((periodic_t){ h, i, (time_t)(NOW+i) });
    log(debug, "added %us periodic handler %p", i, h);
}


bool Periodic::del(handler_t h) {
    for (std::vector<periodic_t>::iterator it = periodic.begin(); it != periodic.end(); ++it) {
        if (it->h == h) {
            periodic.erase(it);
            log(debug, "removed periodic handler %p", h);
            return true;
        }
    }
    return false;
}


//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//


WakeUp* WakeUp::inst = NULL;


void WakeUp::add(handler_t h, void* c) {
    spin_lock(&lock);
    wakeup_t* w = pool.pop();
    w->h = h;
    w->ctx = c;
    w->next = wakeups;
    wakeups = w;
    spin_unlock(&lock);
}


void WakeUp::run() {
    spin_lock(&lock);
    wakeup_t* w = wakeups;
    wakeups = NULL;
    spin_unlock(&lock);
    if (!w) return;

    wakeup_t* i = w;
    while (i) {
        log(io, "wakeup handler %p(%p)", i->h, i->ctx);
        i->h(i->ctx);
        i = i->next;
    }

    spin_lock(&lock);
    while (w) {
        i = w->next;
        pool.push(w);
        w = i;
    }
    spin_unlock(&lock);
}


//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//


Poller* Poller::inst = NULL;


Poller::~Poller() {
    poller_t* p = pollers;
    while (p) {
        (void)p->h(p->ctx);
        poller_t* tmp = p->next;
        pool.push(p);
        p = tmp;
    }
}


void Poller::add(handler_t h, void* c) {
    log(io, "add poll handler %p(%p)", h, c);
    poller_t* p = pool.pop();
    p->h = h;
    p->ctx = c;
    p->next = pollers;
    pollers = p;
}


bool Poller::del(handler_t h, void* c) {
    poller_t* prev = NULL;
    poller_t* p = pollers;
    while (p) {
        if (p->h == h && p->ctx == c) {
            if (prev) {
                prev->next = p->next;
            } else {
                pollers = p->next;
            }
            pool.push(p);
            return true;
        } else {
            prev = p;
            p = p->next;
        }
    }
    return false;
}


void Poller::run() {
    poller_t* prev = NULL;
    poller_t* p = pollers;
    while (p) {
        log(io, "poll handler %p(%p)", p->h, p->ctx);
        if (!p->h(p->ctx)) {
            poller_t* n = p->next;
            if (prev) {
                prev->next = n;
            } else {
                pollers = n;
            }
            pool.push(p);
            p = n;
        } else {
            prev = p;
            p = p->next;
        }
    }
}