#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <cstdio>
#include <deviceManager/deviceManager.h>
#include "deviceAttachmentPipeSpecp.hh"
#include "deviceAttachmentPipeSpecl.hh"

namespace smo {
namespace device {

std::string DeviceManager::readDapSpecFile(const std::string& filename)
{
    std::ifstream file(filename);
    if (!file.is_open())
    {
        throw std::runtime_error(
            std::string(__func__) + ": Couldn't open DAP spec file: "
            + filename);
    }

    std::string content(
        (std::istreambuf_iterator<char>(file)),
        std::istreambuf_iterator<char>());

    return content;
}

void DeviceManager::collateAllDapSpecs(void)
{
    OptionParser &options = OptionParser::getOptions();
    DeviceManager &dm = getInstance();
    dm.s.rsrc.allDapSpecs = options.dapSpecs;

    for (const auto& file : options.dapSpecFiles)
    {
        std::string fileContent = readDapSpecFile(file);
        if (!dm.s.rsrc.allDapSpecs.empty()) {
            dm.s.rsrc.allDapSpecs += "||";
        }
        dm.s.rsrc.allDapSpecs += fileContent;
    }
}

void DeviceManager::parseAllDapSpecs(void)
{
    DeviceManager &dm = getInstance();
    auto file_deleter = [](FILE* f) { if (f) fclose(f); };
    std::unique_ptr<FILE, decltype(file_deleter)> input(
        fmemopen(
            (void*)dm.s.rsrc.allDapSpecs.c_str(),
            dm.s.rsrc.allDapSpecs.size(), "r"),
        file_deleter);

    if (!input)
    {
        throw std::runtime_error(
            std::string(__func__) + ": Failed to fmemopen() a FILE* for "
            "parsing DAP specs");
    }

    deviceAttachmentPipeSpeclin = input.get();
    if (deviceAttachmentPipeSpecpparse())
    {
        throw std::runtime_error(
            std::string(__func__) + ": Failed to parse DAP specs. "
            "Check specs for errors");
    }
}

} // namespace device
} // namespace smo
