#include "ps3000c.hpp"

#include <iostream>
#include <asio.hpp>
#include <spdlog/spdlog.h>

#include <spdlog/sinks/stdout_color_sinks.h>
#include <random>

void run();

using tcp = asio::ip::tcp;

std::shared_ptr<spdlog::logger> const& logger()
{
  static std::shared_ptr<spdlog::logger> logger;
  if (!logger)
    logger = spdlog::stdout_color_mt("console");
  return logger;
}


class peer
{
public:
  peer(std::string const& address)
    : m_socket(m_io_service)
  {
    asio::ip::tcp::resolver resolver(m_io_service);
    asio::connect(m_socket, resolver.resolve(address, "160"));
  }

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

  std::string receive()
  {
#if 1
    auto constexpr END_MARKER = '\n';
    std::string result;
    
    asio::read_until(m_socket, asio::dynamic_buffer(result), '\n');

    if (!result.empty() && result.back() == END_MARKER)
      result.pop_back();

    return result;
#else
    std::string result(1024, '\n');
    auto length = m_socket.receive(asio::buffer(result));
    if (length < result.size())
      result.resize(length);
    return result;
#endif
  }

  std::string query(std::string message)
  {
    command(std::move(message));
    auto response = receive();
    logger()->info("Response \"{0}\"", response);
    return response;
  }

  void command(std::string message)
  {
    auto constexpr DEAD_TIME = std::chrono::milliseconds(100);
    logger()->info("Command \"{0}\"", message);
    message += "\n";
    send(message);
    std::this_thread::sleep_for(DEAD_TIME);
  }

private:
  asio::io_service m_io_service;
  asio::ip::tcp::socket m_socket;
};

void run()
{
  peer p("192.168.0.2");
  p.query("*IDN?");
  p.query("SOUR:CURR?");

  p.command("SYST:LOCK 1");
  p.command("OUTP ON");// Output on!
  p.command("SOUR:CURR 1.0");
  std::this_thread::sleep_for(std::chrono::seconds(2));
  p.command("SOUR:CURR 2.0");
  std::this_thread::sleep_for(std::chrono::seconds(2));
  p.command("SOUR:CURR 3.3"); // WARNING, cannot use commas here
  std::this_thread::sleep_for(std::chrono::seconds(2));
  p.command("SOUR:CURR 0.0");
  //std::this_thread::sleep_for(std::chrono::seconds(1));
  
  p.command("OUTP OFF");// Output off!
  p.command("SYST:LOCK 0");
}
