#pragma once

#include <cstdint>
#include <string>

namespace iosender {

class StreamComms;

class Comms {
public:

    enum class State {
        AwaitAck,
        DataReceived,
        ACK,
        NAK
    };

    enum class ResetMode {
        None,
        DTR,
        RTS
    };

    enum class StreamType {
        Serial,
        Telnet,
        Websocket
    };

    const int TXBUFFERSIZE = 4096;
    const int RXBUFFERSIZE = 1024;

    static void SetCom(StreamComms *com);
    static StreamComms *GetCom();
};

struct DataReceivedHandler {
    virtual void DataReceived(std::string data) = 0;
};

struct ByteReceivedHandler {
    virtual void ByteReceived(int b) = 0;
};

class StreamComms {
public:

    virtual ~StreamComms() = default;

    virtual bool IsOpen() = 0;
    virtual int OutCount() = 0;
    virtual std::string Reply() = 0;
    virtual Comms::StreamType StreamType() = 0;
    virtual bool EventMode() = 0;
    virtual void EventMode(bool mode) = 0;

    virtual void Close() = 0;
    virtual int ReadByte() = 0;
    virtual void WriteByte(uint8_t data) = 0;
    virtual void WriteBytes(uint8_t *bytes, int len) = 0;
    virtual void WriteString(std::string data) = 0;
    virtual void WriteCommand(std::string command) = 0;
    virtual std::string GetReply(std::string command) = 0;
    virtual void AwaitAck() = 0;
    virtual void AwaitAck(std::string command) = 0;
    virtual void AwaitResponse(std::string command) = 0;
    virtual void AwaitResponse() = 0;
    virtual void PurgeQueue() = 0;

    Comms::State CommandState = Comms::State::NAK;
    DataReceivedHandler *dataReceivedHandler = nullptr;
    ByteReceivedHandler *byteReceivedHandler = nullptr;
};


}