#include "luastack.hpp"
#include "globaldb.hpp"

LuaDefine(global_once, "string", "for a given string, returns true exactly once") {
    LuaArg name;
    LuaRet flag;
    LuaVar oncedb, val;
    LuaStack LS(L, name, flag, oncedb, val);

    // Get a pointer to the oncedb.
    LS.rawget(oncedb, LuaRegistry, "oncedb");
    if (!LS.istable(oncedb)) {
        LS.set(flag, false);
        return LS.result();
    }

    LS.checkstring(name);
    LS.rawget(val, oncedb, name);
    if (!LS.isnil(val)) {
        LS.set(flag, false);
        return LS.result();
    }
    LS.rawset(oncedb, name, true);
    LS.set(flag, true);
    return LS.result();
}

LuaDefine(global_clearonce, "name", "reset the specified once-flag") {
    LuaArg name;
    LuaVar oncedb;
    LuaStack LS(L, name, oncedb);

    // Get a pointer to the oncedb.
    LS.rawget(oncedb, LuaRegistry, "oncedb");
    if (!LS.istable(oncedb)) {
        return LS.result();
    }
    LS.checkstring(name);
    LS.rawset(oncedb, name, LuaNil);
    return LS.result();
}

LuaDefine(global_table, "globalname", "get a table where global data can be stored") {
    LuaArg globalname;
    LuaRet globaltab;
    LuaVar globaldb;
    LuaStack LS(L, globalname, globaltab, globaldb);

    // Get a pointer to the globaldb.
    LS.rawget(globaldb, LuaRegistry, "globaldb");
    if (!LS.istable(globaldb)) {
        return lua_yield(L, 0); // donotpredict
    }

    LS.checkstring(globalname);

    // Get the globaltab from the globaldb, sanity check it.
    LS.rawget(globaltab, globaldb, globalname);
    if (LS.istable(globaltab)) {
        return LS.result();
    } else if (!LS.isnil(globaltab)) {
        luaL_error(L, "%s is not a global", LS.ckstring(globalname).c_str());
    }

    // Create a new globaltab and store it in the globaldb.
    LS.newtable(globaltab);
    LS.rawset(globaldb, globalname, globaltab);
    LS.rawset(globaltab, "__global", globalname);
    LS.settabletype(globaltab, LUA_TT_GLOBALDB);
    return LS.result();
}
