#include "guided_scheduler.hpp"

#include <boost/thread.hpp>

namespace {

struct GuidedState {
    int F;
    int K;
    int next_frame;
    boost::mutex mtx;
};

struct GuidedArgs {
    int tid;
    GuidedState* st;
    task_fn_t task;
    void* ctx;
    bool affinity;
};

void worker(GuidedArgs a) {
    if (a.affinity)
        set_thread_affinity(a.tid);

    while (true) {
        int start, end;
        {
            boost::mutex::scoped_lock lk(a.st->mtx);
            if (a.st->next_frame >= a.st->F)
                return;

            int remaining = a.st->F - a.st->next_frame;
            int chunk = remaining / a.st->K;
            if (chunk < 1) chunk = 1;

            start = a.st->next_frame;
            a.st->next_frame += chunk;
            end = a.st->next_frame;
            if (end > a.st->F) end = a.st->F;
        }

        for (int f = start; f < end; ++f)
            a.task(f, a.tid, a.st->K, a.ctx);
    }
}

} // namespace

int run_guided_scheduler(int F, int K, task_fn_t task, void* ctx, bool affinity)
{
    if (F <= 0 || K <= 0 || task == nullptr)
        return -1;

    GuidedState st;
    st.F = F;
    st.K = K;
    st.next_frame = 0;

    boost::thread_group workers;
    for (int tid = 0; tid < K; ++tid) {
        GuidedArgs a{tid, &st, task, ctx, affinity};
        workers.create_thread(boost::bind(worker, a));
    }
    workers.join_all();
    return 0;
}
