#include <iostream>
#include <emscripten/heap.h>

#include <fugg.h>
#include <flyff.h>

#include <emscripten.h>
#include <emscripten/bind.h>

// #include "client.h"

#define TRACE_ALLOC 0

void *malloc(size_t size) {
// void * operator new(std::size_t size) {
    // This malloc is always called from the runtime.

    if ((*flyff::malloc) != nullptr) {
        // Since this malloc is always called from the interop, we need to 
        // transform it to point to the actual address where the WASM runtime memory
        // resides.

        const auto &ptr = fugg::ModulePointer<void>{
                (*flyff::malloc)(size)
        };

#if TRACE_ALLOC
        std::cout << "FLYFF: Allocated INSIDE " << size << " bytes at " << reinterpret_cast<void*>(ptr.as_raw()) << std::endl;
#endif

        return ptr;
    } else {
        auto ptr = emscripten_builtin_malloc(size);

#if TRACE_ALLOC
        std::cout << "FUGG: Allocated OUTSIDE " << size << " bytes at " << reinterpret_cast<void*>(ptr) << std::endl;
#endif

        return ptr;
    }
}

void free(void *ptr_) {

    if ((*flyff::free) != nullptr) {
        const auto &ptr = fugg::RuntimePointer<void>{ptr_};

        (*flyff::free)(ptr.as_raw());

#if TRACE_ALLOC
        std::cout << "FLYFF: Free'd INSIDE pointer at " << reinterpret_cast<void*>(ptr.as_raw()) << std::endl;
#endif
    } else {
        emscripten_builtin_free(ptr_);

#if TRACE_ALLOC
        std::cout << "FUGG: Free'd OUTSIDE pointer at " << reinterpret_cast<void*>(ptr) << std::endl;
#endif
    }
}

void get_text(const std::string& text) {
    const auto &neuz = flyff::Neuz::instance();

    const auto &result = neuz.get_text(text);

    std::cout << text << " = \"" << result << "\"" << std::endl;
}

EMSCRIPTEN_BINDINGS(fugg) {
    emscripten::function("get_text", &get_text);
};

int main() {
    using flyff::Neuz;

    std::cout << "Hello world from fugg!" << std::endl;
    std::cout << "Initialising runtime... ";

    auto &neuz = Neuz::instance();

    std::cout << "Ok!" << std::endl;

    std::cout << "Starting Flyff..." << std::endl;
    return neuz.main();
}