#ifndef MR4TH_COROUTINE_H
#define MR4TH_COROUTINE_H

////////////////////////////////
// Coroutine Types

typedef void CO_Func(void *param);

typedef U32 CO_State;
enum{
    CO_State_Dead,
    CO_State_Active,
    CO_State_Inactive,
    CO_State_Waiting,
};

typedef struct CO_Coroutine{
    struct CO_Coroutine *next;
    CO_Func *func;
    void    *param;
    void    *udata;
    void    *in;
    void    *out;
    CO_State state;
    
    TH_Thread thread;
    TH_CondVar cv;
} CO_Coroutine;

typedef struct CO_Ctx{
    U32 size;
    B32 did_init;
    CO_Coroutine *buf;
    CO_Coroutine *ptr;
    CO_Coroutine *opl;
    CO_Coroutine *free;
    CO_Coroutine *active;
    CO_Coroutine  root;
    
    TH_Mutex mutex;
    TH_CondVar cv;
} CO_Ctx;


////////////////////////////////
// Coroutine Functions

MR4TH_SYMBOL_STATIC B32  co_ctx_init(U64 max_co_count);
MR4TH_SYMBOL_STATIC void co_ctx_release(void);

MR4TH_SYMBOL_STATIC CO_Coroutine* co_create(CO_Func *func, void *param, void *udata);
MR4TH_SYMBOL_STATIC CO_Coroutine* co_run(CO_Coroutine *co, void *in, void *out);

MR4TH_SYMBOL_STATIC void  co_yield(void);
MR4TH_SYMBOL_STATIC CO_Coroutine* co_me(void);
MR4TH_SYMBOL_STATIC void* co_param(void);
MR4TH_SYMBOL_STATIC void* co_udata(void);
MR4TH_SYMBOL_STATIC void* co_in(void);
MR4TH_SYMBOL_STATIC void* co_out(void);

MR4TH_SYMBOL_STATIC CO_Coroutine* co__alloc(CO_Ctx *ctx);
MR4TH_SYMBOL_STATIC void          co__pass_control_to(CO_Coroutine *co);
MR4TH_SYMBOL_STATIC void          co__wait_until_active(CO_Ctx *ctx, CO_Coroutine *co);
MR4TH_SYMBOL_STATIC void          co__wait_for_init(CO_Ctx *ctx);

#endif //MR4TH_COROUTINE_H
