#include <memory>
#include <dlfcn.h>

#include "eval_cpp.h"
#include "util.h"
#include "log.h"
#include "file.h"
#include "show.h"

Eval_cpp::Eval_cpp(Machine& machine, const Locator& loc)
    : m_machine(machine)
    , m_loc(loc)
{
    (void)K::log(3);
}

std::string Eval_cpp::eval(const fs::path& library_path, const std::string& function_name)
{
    (void)K::log(3, library_path, function_name);
    // msg() << "library path: " << library_path.string().c_str() << "\n";
    void* handle = dlopen(library_path.string().c_str(), RTLD_LAZY);
    if (!handle) {
        const char* error = dlerror();
        std::string error_desc = error ? error : "unknown error";
        throw File_error("Cannot open library: " + library_path.string() + "\n  " + error_desc, m_loc);
    }
    dlerror();
    typedef std::string (*func_t)(Machine);
    func_t func = (func_t) dlsym(handle, function_name.c_str());
    const char* dlsym_error = dlerror();
    if (dlsym_error) {
        std::string error_desc(dlsym_error);
        dlclose(handle);
        std::stringstream ss {};
        ss << "Cannot load symbol " << function_name
           << " from library " << library_path << ":\n  " << error_desc;
        throw File_error(ss.str(), m_loc);
    }
    std::string result = func(m_machine);
    dlclose(handle);
    return result;
}

