#include "chunk_scheduler.hpp"

#include <boost/thread.hpp>

namespace {

const int CHUNK = 8;

struct ChunkState {
    int F;
    int next_frame;
    boost::mutex mtx;
};

struct ChunkArgs {
    int tid;
    int K;
    ChunkState* st;
    task_fn_t task;
    void* ctx;
    bool affinity;
};

void worker(ChunkArgs 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;
            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.K, a.ctx);
    }
}

} // namespace

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

    ChunkState st;
    st.F = F;
    st.next_frame = 0;

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