#include <stdio.h>
#include <stddef.h>
#include "coroutine.h"
#include "generator.h"
#include "asleep.h"
#include "task.h"

#include <dirent.h> 
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define DEMO_STACK_SIZE (8192*sizeof(void *))

void *stack_inner(void *param){
    printf("%td) Inner headroom (big stack now) = %td\n", (ptrdiff_t)param, Coroutine_GetStackHeadroom());
    // Stack may be trimmed here...
    Generator_Yield(0);
    printf("%td) Inner headroom (stack may be trimmed) = %td\n", (ptrdiff_t)param, Coroutine_GetStackHeadroom());
    return NULL;
}

void *stack_outer(void *param){
    printf("%td) Outer headroom (start) = %td\n", (ptrdiff_t)param, Coroutine_GetStackHeadroom());
    Generator_Yield(0);
    printf("%td) Outer headroom (may be trimmed) = %td\n", (ptrdiff_t)param, Coroutine_GetStackHeadroom());
    Coroutine_CallWithMaxStack(stack_inner, param, NULL);
    printf("%td) Outer headroom (return from call) = %td\n", (ptrdiff_t)param, Coroutine_GetStackHeadroom());
    return NULL;
}


void *chaintest(
    void *param
){
    (void)param;

    // Need to run two coroutines so that at least one of their stacks is limited, and so
    // needs to chain
    Generator gen1;
    Generator_ctor(&gen1, DEMO_STACK_SIZE, 0, stack_outer, (void *)0);
    Generator gen2;
    Generator_ctor(&gen2, DEMO_STACK_SIZE, 0, stack_outer, (void *)1);
    void *param1;
    void *param2;
    while(Generator_Next(&gen1, &param1) && Generator_Next(&gen2, &param2)){
    }
    Generator_dtor(&gen2);
    Generator_dtor(&gen1);

    return param;
}


int main(int argc, char *argv[]) {
    (void)argc;
    (void)argv;

    Coroutine_Run(DEMO_STACK_SIZE, 0, chaintest, NULL, NULL);

    return 0;
}
