#include <myapp/rcon/unixprovider.h>
#include <myapp/rcon/unixconnection.h>
#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

namespace myapp::rcon {

std::unique_ptr<unix_provider> unix_provider::create(std::shared_ptr<myapp::async::event_loop> loop)
{
    return std::make_unique<unix_provider>(async::pipe::create(loop));
}

unix_provider::unix_provider(std::unique_ptr<myapp::async::pipe> pipe)
  : pipe_(std::move(pipe))
  , callback_([](auto conn_ptr) { })
  , error_handler_([](auto err_str) { })
{
    set_error_handler();
}

void unix_provider::server(std::string endpoint)
{
    pipe_->bind(fs::u8path(endpoint));
    pipe_->listen(1, [this]
    {
        callback_(std::make_unique<unix_connection>(pipe_->accept()));
    });
}

void unix_provider::client(std::string endpoint)
{
    pipe_->connect(fs::u8path(endpoint), [this]
    {
        callback_(std::make_unique<unix_connection>(std::move(pipe_)));
    });
}

void unix_provider::set_error_handler()
{
    pipe_->on_error([this](auto async_result)
    {
        try { async_result(); }
        catch (std::exception& e) {
            error_handler_(e.what());
        }
    });
}

void unix_provider::on_callback(std::function<void(std::unique_ptr<connection>)> handler)
{
    callback_ = std::move(handler);
}

void unix_provider::on_error(std::function<void(std::string)> handler)
{
    error_handler_ = std::move(handler);
}

} /* namespace myapp::rcon */
