#define _DEFAULT_SOURCE // usleep()
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include "include/raylib.h"
#include "include/raymath.h"
#include "boids_game.h"

const char* GAME_LIB = "./libboids.so";

struct Game {
    void* handle;
    ino_t gamelib_id;
    struct GameApi api;
    struct GameState* state;
};

void load_game(struct Game* game) {
    struct stat attr;
    if ((stat(GAME_LIB, &attr) == 0) && (game->gamelib_id != attr.st_ino)) {
        usleep(10000);
        if (game->handle) {
            game->api.unload(game->state);
            dlclose(game->handle);
        }
        void* handle = dlopen(GAME_LIB, RTLD_NOW);
        if (handle) {
            game->handle = handle;
            game->gamelib_id = attr.st_ino;
            const struct GameApi* api = dlsym(game->handle, "GAME_API");
            if (api != NULL) {
                printf("Loaded API, calling init()\n");
                game->api = *api;
                if (game->state == NULL) {
                    game->state = game->api.init();
                }
                game->api.reload(game->state);
            } else {
                printf("Failed to load API\n");
                dlclose(game->handle);
            }
        } else {
            fprintf(stderr, "Error loading %s\n", GAME_LIB);
            fprintf(stderr, "Error was: %s\n", dlerror());
            exit(1);
        }
    }
}

int main(void) {
    struct Game game = {0};
    while (1) {
        load_game(&game);
        if (game.api.window_should_close()) {
            break;
        }
        game.api.step(game.state);
    }
    game.api.finalize(game.state);
    free(game.state);
}
