#include "twn_game_object_c.h"
#include "twn_engine_context_c.h"
#include "twn_util_c.h"

#include <errhandlingapi.h>
#include <libloaderapi.h>


#define GAME_OBJECT_PATH "libgame.dll"


static void (*game_tick_callback)(void);
static void (*game_end_callback)(void);

static void *handle = NULL;


static void load_game_object(void) {
    /* needs to be closed otherwise symbols aren't resolved again */
    if (handle) {
        FreeLibrary(handle);
        handle = NULL;
        game_tick_callback = NULL;
        game_end_callback = NULL;
    }

    void *new_handle = LoadLibraryA(GAME_OBJECT_PATH);
    if (!new_handle) {
        log_critical("Hot Reload Error: Cannot open game code shared object (%s)", GetLastError());
        goto ERR_OPENING_SO;
    }

#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wpedantic"

    game_tick_callback = (void (*)(void))GetProcAddress(new_handle, "game_tick");
    if (!game_tick_callback) {
        CRY("Hot Reload Error", "game_tick_callback() symbol wasn't found");
        goto ERR_GETTING_PROC;
    }

    game_end_callback = (void (*)(void))GetProcAddress(new_handle, "game_end");
    if (!game_end_callback) {
        CRY("Hot Reload Error", "game_end_callback() symbol wasn't found");
        goto ERR_GETTING_PROC;
    }

#pragma GCC diagnostic pop

    handle = new_handle;

    if (ctx.game.frame_number != 0)
        log_info("Game object was reloaded\n");

    return;

ERR_GETTING_PROC:
    FreeLibrary(new_handle);
    game_tick_callback = NULL;
    game_end_callback = NULL;

ERR_OPENING_SO:
    die_abruptly();
}


void game_object_load(void) {
    load_game_object();
}


void game_object_unload(void) {
    game_end_callback();
    FreeLibrary(handle);
    handle = NULL;
    game_tick_callback = NULL;
    game_end_callback = NULL;
}


/* doesn't support reloading because of problems with file watching */
bool game_object_try_reloading(void) {
    return false;
}


void game_object_tick(void) {
    game_tick_callback();
}
