#pragma once

#include <string>
#include <thread>
#include <queue>

namespace grbl {

struct transport;

struct transport_callbacks {
    virtual void on_connected(transport *) = 0;
    virtual void on_disconnected(transport *) = 0;
    virtual void on_line_received(std::string line, transport *) = 0;
};

struct transport {
    virtual ~transport() = default;
    virtual void open(transport_callbacks& cb) = 0;
    virtual void close() = 0;
    virtual void send(std::string line) = 0;
    virtual void send_single_char_command(uint8_t data) const = 0;
};

struct tcp_transport : public transport {
    tcp_transport(std::string address, uint16_t port);
    virtual ~tcp_transport();

    void open(transport_callbacks& cb) override;
    void close() override;
    void send(std::string line) override;
    void send_single_char_command(uint8_t data) const override;

    void request_realtime_report();
    void request_cycle_start();
    void request_feed_hold();
    void parser_state_report();

private:

    void worker();

    std::string ip;
    uint16_t port;
    transport_callbacks *listener = nullptr;
    int fd = -1;
    volatile bool is_connected = false;
    std::thread live_check_thread;
    std::queue<std::string> send_queue;
    volatile bool should_quit = false;
    static bool is_empty_line(const std::string& line);
};

}

