#include "vm_provider.hpp"
#include "vm.hpp"
#include <mutex>
#include <thread>

using namespace sliger::rpc;

auto VmProvider::load_and_start(std::vector<uint32_t> instructions) -> void
{
    std::lock_guard lock(this->mutex);

    if (this->running_thread) {
        this->vm = {};
        this->running_thread = {};
    }

    this->vm.emplace(instructions,
        VMOpts {
            .flame_graph = true,
            .code_coverage = true,
            .print_debug = false,
        });

    this->running_thread = std::thread([&]() {
        while (not this->done()) {
            this->run_timeslot();
        }
    });
}

auto VmProvider::flame_graph_json() -> std::optional<std::string>
{
    std::lock_guard lock(this->mutex);

    if (this->vm) {
        return this->vm->flame_graph_json();
    } else {
        return {};
    }
}

auto VmProvider::code_coverage_json() -> std::optional<std::string>
{
    std::lock_guard lock(this->mutex);

    if (this->vm) {
        return this->vm->code_coverage_json();
    } else {
        return {};
    }
}

void VmProvider::run_timeslot()
{
    std::lock_guard lock(this->mutex);

    if (not this->vm)
        return;

    this->vm->run_n_instructions(100);
}

auto VmProvider::done() -> bool
{
    std::lock_guard lock(this->mutex);

    return not this->vm.has_value() or this->vm->done();
}
