// calogLuaEngine.c -- bridges the Lua adapter to the actor layer's CalogEngineT vtable.
//
// Every hook here runs on the owning context's thread (createInterpreter,
// runSource, destroyInterpreter), which is what confines the lua_State to one
// thread. createInterpreter builds the state and exposes the configured natives;
// runSource evaluates a script and reports failure through the single error
// channel (result).

#include "calogInternal.h"
#include "luaAdapter.h"

static int32_t luaEngineCreate(CalogContextT *context, void **interpOut);
static void    luaEngineDestroy(void *interp);
static int32_t luaEngineRun(void *interp, const char *source, CalogValueT *result);
static void    luaExposeVisitor(const CalogEntryT *entry, void *ud);

static const char *const luaExtensions[] = { "lua", NULL };

const CalogEngineT calogLuaEngine = {
    "lua",
    luaExtensions,
    luaEngineCreate,
    luaEngineDestroy,
    luaEngineRun
};


static int32_t luaEngineCreate(CalogContextT *context, void **interpOut) {
    CalogLuaT *lc;
    int32_t    status;

    *interpOut = NULL;
    status = calogLuaCreate(&lc, calogContextBroker(context), calogContextId(context));
    if (status != calogOkE) {
        return status;
    }
    calogForEach(calogContextBroker(context), luaExposeVisitor, lc);
    *interpOut = lc;
    return calogOkE;
}


static void luaExposeVisitor(const CalogEntryT *entry, void *ud) {
    calogLuaExpose((CalogLuaT *)ud, entry->name);
}


static void luaEngineDestroy(void *interp) {
    calogLuaDestroy((CalogLuaT *)interp);
}


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

    calogValueNil(result);
    status = calogLuaRun((CalogLuaT *)interp, source);
    if (status != calogOkE) {
        // calogLuaRun has already written the detailed diagnostic to stderr; surface a
        // status-bearing error through the single channel.
        return calogFail(result, status, "lua script failed");
    }
    return calogOkE;
}
