#ifndef APISMTCPCLIENT_H
#define APISMTCPCLIENT_H

#include <QObject>

#include <QTcpSocket>
#include <QAbstractSocket>
#include <QByteArray>
#include <QQueue>

class QTimer;


class ApismMessage
{
public:

    enum class MessageState {
        INVALID,
        NEW,
        SENT,
        ANSWERED,
        RESEND
     };
     MessageState state;

     QByteArray data;

     ApismMessage();
};




class ApismTcpClient : public QObject
{
    Q_OBJECT

public:
    enum class ExpectedResponse {
        JSON,
        STATE
     };

    explicit ApismTcpClient(const QString & hostname, const QString & port, ExpectedResponse expectedResponse, QObject *parent = nullptr);
    bool isConnected();

    void connectToHost();
    void connectToHost(const QString & hostname, const QString & port);
    void setResponseTimeout(const quint32 timeout_ms);

    // socket is implicitely closed by APISM
    void closeConnection();

    void sendData(const QByteArray & message);
    void sendData();

    void setDebug(bool debug);

private slots:
    // socket interface
    void onSocketConnected();
    void onSocketDisconnected();
    void onSocketBytesWritten(qint64 bytes);
    void onSocketReadyRead();
    void onSocketStateChanged(QAbstractSocket::SocketState socketState);
    void onSocketErrorOccured(QAbstractSocket::SocketError socketError);

signals:
    void receivedData(QByteArray response);

    void responseTimeout();
    void connectTimeout();
    void connectionClosedByRemoteHost();
    void connectionRefusedError();

private:
    QTcpSocket *socket;

    QQueue<QByteArray> sendQueue;
    ApismMessage currentMessage;

    QString hostname;
    QString port;

    QTimer *responseTimeoutTimer;
    quint8 responseTimerTimeoutCounter;

    QTimer *connectTimeoutTimer;

    void private_sendData();
    bool flag_selfClosed;

    int resendCounter;
    int connectionRefusedCounter;

    ExpectedResponse expectedResponse;

    void private_handleJSONResponse(QByteArray & responseMessage);
    void private_handleTextResponse(QByteArray & responseMessage);
    void private_handleStateResponse(QByteArray & responseMessage);

    void private_handleConnectionRefusedError();

    bool isDebug;

public slots:
    void onResponseTimeoutTimerTimeout();
    void onConnectTimeoutTimerTimeout();

};

QDebug operator<<(QDebug debug, ApismTcpClient::ExpectedResponse response);


#endif // APISMTCPCLIENT_H