#pragma once

#include <cstdint>
#include <memory>
#include <vector>
#include <string>

#include "data_format.hpp"
#include "itransport.hpp"

class Controller {
public:
    Controller();
    ~Controller() = default;

    // connection
    bool connect(const std::string& host, std::uint16_t port = 502);
    void disconnect();
    bool is_connected() const;

    // raw register access
    bool read_register(std::uint16_t addr, std::uint16_t& value);
    bool write_register(std::uint16_t addr, std::uint16_t value);

    // 32-bit
    bool read_int32(std::uint16_t addr,
                    std::int32_t& value,
                    const DataFormat& fmt);

    bool write_int32(std::uint16_t addr,
                     std::int32_t value,
                     const DataFormat& fmt);

    bool read_uint32(std::uint16_t addr,
                     std::uint32_t& value,
                     const DataFormat& fmt);

    bool write_uint32(std::uint16_t addr,
                      std::uint32_t value,
                      const DataFormat& fmt);

    // float / double
    bool read_float(std::uint16_t addr,
                    float& value,
                    const DataFormat& fmt);

    bool write_float(std::uint16_t addr,
                     float value,
                     const DataFormat& fmt);

    bool read_double(std::uint16_t addr,
                     double& value,
                     const DataFormat& fmt);

    bool write_double(std::uint16_t addr,
                      double value,
                      const DataFormat& fmt);

    // 64-bit
    bool read_int64(std::uint16_t addr,
                    std::int64_t& value,
                    const DataFormat& fmt);

    bool write_int64(std::uint16_t addr,
                     std::int64_t value,
                     const DataFormat& fmt);

    bool read_uint64(std::uint16_t addr,
                     std::uint64_t& value,
                     const DataFormat& fmt);

    bool write_uint64(std::uint16_t addr,
                      std::uint64_t value,
                      const DataFormat& fmt);

private:
    bool connected_{false};
    std::string host_;
    std::uint16_t port_{502};

    std::unique_ptr<ITransport> transport_;
};
