/* KallistiOS ##version##

   hello.c
   (c)2001 Dan Potter
*/

#include <kos.h>

#include "Lua/lua.h"
#include "Lua/lualib.h"
#include "Lua/lauxlib.h"


KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS);

// Pointer to our lua state.
lua_State * luaState;


/* This function will be seen by Lua as "DcWrite".
 * In Lua, the only arg is a string for what to print. 
 * Any C function you write for lua to use will have this prototype. 
 */
static int lua_DcWrite(lua_State * L)
{
    /* Lua internally operates as a stack when it passes stuff to 
     * functions.  The string is the first on the stack. 
     * luaL_checklstring will not only check that there is a string there
     * (and throw a very well managed error if it isn't) it
     * will also store the string into our C data. 
     * Strings that come from lua are still managed from it so we
     * don't have to delete the string or anything. */
    size_t msgLength = 0;
    const char * msg;
    msg = luaL_checklstring(L, 1, &msgLength);
    printf(msg);
    return 0;
}

/* The luaL_Reg structure is used to tell lua how to communicate
 * with a C function. */
static const struct luaL_Reg dcLib[] = {
    { "Write", lua_DcWrite},
    { NULL, NULL } /* Sentinel */
};

/* Registers our own non-standard functions into lua. */
static int luaOpenDcLibs(lua_State * L)
{
   luaL_register(L, "Dreamcast", dcLib);
   return 1;
}


/* This function is used by lua_load to load in a file.
 * This lets us give lua_load a way to load from any data source
 * we want. */
const char * luaFileReader(lua_State * L, void * data, size_t * size)
{
    static char luaReaderText[256];
    luaReaderText[255] = '\0';
    
    // When we call lua_load we can pass it anything as a void pointer.
    // Here we pass in a file, so let's read from that file here.
    FILE * fp = (FILE *) data;
    
    // Read the data into the buffer here.
    // Let lua know what size the data read was by changing "*size".
    *size = fread(luaReaderText, 1, 255, fp);
    luaReaderText[*size] = '\0';
   
    return (const char *) luaReaderText;
}

// eCode is the error code returned by lua_Resume()
static void showLuaError(int eCode)
{
   if (luaState == NULL)
       return;
   if (eCode == LUA_ERRSYNTAX)
   {
       printf("Syntax error!\n\n");
   }
   if (eCode == LUA_ERRRUN)
   {   
       printf("Runtime error.\n\n");
   }
   if (eCode == LUA_ERRMEM)
   {
       printf("Memory allocation error.\n\n");
   }
   if (eCode == LUA_ERRERR)
   {
       printf("Error handler function error.\n\n");
   }
   const char * errorMsg = 
       luaL_checkstring(luaState, -1);
   if (errorMsg != NULL)
   {
       printf("%s", errorMsg);
   }
   else
   {
       printf("Error message not available.\n\n");
   }
}

void pressAtoQuit()
{
     /* Routines to hit the control pad. */
    printf("Hit button A on control pad 1 to finish.\n\n");
    fflush(stdout);
    int numPlayers = 1;
    maple_device_t * controllers[numPlayers];
    cont_state_t * state[numPlayers];
    
    for (int i = 0; i < numPlayers; i ++)
    {     
          controllers[i] = maple_enum_type(i, MAPLE_FUNC_CONTROLLER);
    } 
    
    bool quit = false;
    while(!quit)
    {
       state[0] = (cont_state_t *)(maple_dev_status(controllers[0]));
       if ((state[0]->buttons & CONT_A))
       {
          quit = true;
       }
    }
}

/* Your program's main entry point */
int main(int argc, char **argv) {
	/* The requisite line */
	printf("\nHello world in C!\n\n");
    
    luaState = luaL_newstate();
    // Opens all the "standard" lua libraries.  I don't know much about those.
    luaL_openlibs(luaState);
    // Makes Lua aware of our own lua functions!
    luaOpenDcLibs(luaState);
    
    // Lua has a very generic function to load in a lua script and lucky
    // for us it accepts a function we can easily create to send in chars.
    lua_Reader reader = luaFileReader;
    
    // We read in a file from the ethernet cable, if you have one.
    // This assumes the file lives at "C:\DcSimpleLua" so you'll probably
    // have to change it.
    fs_chdir("/pc/cygdrive/c/DcSimpleLua");
    
    FILE * fp = fopen("luascript.lua", "rb");
    
    if (fp == NULL)
    {
        printf("FILE NOT FOUND!\n\n");
        pressAtoQuit();
        return 0;
    }
    
    // The last arg is the chunk name, used for debug info if Lua
    // gives you any error msgs.
    int eCode = 
        lua_load(luaState, reader, ((void *)fp), "luascript.lua\n\n");
    
    // Close file.
    fclose(fp);
    
    if (eCode != 0)
    {
        showLuaError(eCode);
        printf("Uh oh, the script had ERRORS!\n\n");
        pressAtoQuit();
        return 0;
    }
    
    // Starts a lua "thread."  You can push args onto the luaState's
    // stack and increase the last parm number although that isn't applicable
    // here.  Lua will run until it encounters a "yield" keyword.
    eCode = lua_resume(luaState, 0);
    
    // Close lua.
    if (luaState != NULL)
        lua_close(luaState);
    luaState = NULL;
    
    printf("\n\n");
    printf("The end!\n\n");
    
    pressAtoQuit();
    
	return 0;
}


