#include "../context.h"
#include <stdio.h>

Iterator* createOneDimIterator(struct Context* context, int x) {
    struct Iterator* iterator = new Iterator();
    struct OneDimIterator* oneDimIterator = new OneDimIterator();
    iterator->iterator = (union Data*)oneDimIterator;
    iterator->exec = C_execOneDimIterator;
    iterator->barrier = C_barrierOneDimIterator;
    oneDimIterator->x = x;
    oneDimIterator->count = x;
    oneDimIterator->loopCounter = new LoopCounter();
    oneDimIterator->loopCounter->i = 0;
    return iterator;
}

__code execOneDimIterator(struct OneDimIterator* iterator, struct TaskManager* taskManager, struct Context* task, __code next(...)) {
    if (iterator->loopCounter->i == iterator->x) {
        iterator->loopCounter->i = 0;
        goto next(...);
    }
    struct Context* iterate_task = NEW(struct Context);
    *iterate_task = *task;
    task->iterate = 1;
    iterator->loopCounter->i++;
    taskManager->taskManager = (union Data*)task->taskManager;
    taskManager->context = iterate_task;
    taskManager->next = C_execOneDimIterator;
    goto meta(context, task->taskManager->spawn);
}

__code execOneDimIterator_stub(struct Context* context) {
    OneDimIterator* iterator = (OneDimIterator*)GearImpl(context, Iterator, iterator);
    TaskManager* taskManager = Gearef(context, TaskManager);
    Context* task = Gearef(context, Iterator)->task;
    enum Code next = Gearef(context, Iterator)->next;
    goto execOneDimIterator(context, iterator, taskManager, task, next);
} 

__code barrierOneDimIterator(struct OneDimIterator* iterator, struct Context* task, __code next(...), __code whenWait(...)) {
    if (__sync_fetch_and_sub(&iterator->count, 1) == 1) {
        goto next(...);
    }
    goto whenWait(...);
}

__code barrierOneDimIterator_stub(struct Context* context) {
    OneDimIterator* iterator = (OneDimIterator*)GearImpl(context, Iterator, iterator);
    Context* task = Gearef(context, Iterator)->task;
    enum Code next = Gearef(context, Iterator)->next;
    enum Code whenWait = Gearef(context, Iterator)->whenWait;
    goto barrierOneDimIterator(context, iterator, task, next, whenWait);
}