// mrubyEngine.c -- bridges the mruby adapter to the actor layer's CalogEngineT vtable.
//
// Every hook runs on the owning context's thread (createInterpreter, runSource,
// destroyInterpreter), confining the mruby VM (one mrb_state) to one thread. createInterpreter
// builds the VM and exposes the registered natives; runSource evaluates a script and reports
// failure through the single error channel (result).

#include "calogInternal.h"
#include "mrubyAdapter.h"

static int32_t mrubyEngineCreate(CalogContextT *context, void **interpOut);
static void    mrubyEngineDestroy(void *interp);
static int32_t mrubyEngineRun(void *interp, const char *source, CalogValueT *result);
static void    mrubyExposeVisitor(const CalogEntryT *entry, void *ud);

static const char *const mrubyExtensions[] = { "rb", NULL };

const CalogEngineT calogMrubyEngine = {
    "mruby",
    mrubyExtensions,
    mrubyEngineCreate,
    mrubyEngineDestroy,
    mrubyEngineRun
};


static int32_t mrubyEngineCreate(CalogContextT *context, void **interpOut) {
    CalogMrubyT *rb;
    int32_t      status;

    *interpOut = NULL;
    status = calogMrubyCreate(&rb, calogContextBroker(context), calogContextId(context));
    if (status != calogOkE) {
        return status;
    }
    calogForEach(calogContextBroker(context), mrubyExposeVisitor, rb);
    *interpOut = rb;
    return calogOkE;
}


static void mrubyEngineDestroy(void *interp) {
    calogMrubyDestroy((CalogMrubyT *)interp);
}


static int32_t mrubyEngineRun(void *interp, const char *source, CalogValueT *result) {
    int32_t status;

    calogValueNil(result);
    status = calogMrubyRun((CalogMrubyT *)interp, source);
    if (status != calogOkE) {
        return calogFail(result, status, "mruby script failed");
    }
    return calogOkE;
}


static void mrubyExposeVisitor(const CalogEntryT *entry, void *ud) {
    calogMrubyExpose((CalogMrubyT *)ud, entry->name);
}
