#include "SerialConnection.hpp"
#include "Logger.hpp"

using namespace schneide;

SerialConnection::SerialConnection(
  std::string const& deviceName, std::string portName, char lineTerminator) try
: mPortName(portName),
  mLineTerminator(lineTerminator),
  mPort(mIoService, mPortName)
{
  // Check connection
  if (mPort.is_open())
    Logger::get()->info("Connected {0} on {1}", deviceName, portName);
  else
    throw std::runtime_error(
      fmt::format("Unable to connect to {0} on {1}", deviceName, portName));

  mPort.set_option(asio::serial_port::baud_rate(9600));
  mPort.set_option(asio::serial_port::parity(asio::serial_port::parity::none));
  mPort.set_option(
    asio::serial_port::stop_bits(asio::serial_port::stop_bits::one));
  mPort.set_option(asio::serial_port::character_size(8));
}
catch (std::system_error const& e)
{
  throw std::runtime_error(
    fmt::format("Unable to open serial connection to {0} on {1}: {2}",
      deviceName, portName, e.what()));
}

std::string SerialConnection::query(std::string message)
{
  Logger::get()->info("Sending \"{0}\"", message);
  message += mLineTerminator;
  send(message);
  auto response = receive();

  // Remove newline chars from the response
  response.erase(std::remove_if(response.begin(), response.end(),
                   [](char x) { return x == '\n' || x == '\r'; }),
    response.end());

  Logger::get()->info("Response \"{0}\"", response);
  return response;
}

void SerialConnection::send(std::string const& message)
{
  asio::write(mPort, asio::buffer(message));
}

std::string SerialConnection::receive()
{
  std::string result;

  auto length =
    asio::read_until(mPort, asio::dynamic_buffer(result), mLineTerminator);

  return result;
}
