/**
 * Copyright (c) 2022
 *    Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 *    Abrar (https://gitlab.com/s96abrar)
 *    rahmanshaber (https://gitlab.com/rahmanshaber)
 *
 * This code is inspired from
 * https://github.com/monicaphalswal/unix-domain-socket-chat-client-server
 *
 * DFL::IPC::Client is unix domain socket based client, wrapped in Qt/C++
 * class for convenience of use. This class is used in conjunction with
 * DFL::IPC:Server to communicate between two instances of the same app.
 **/

#pragma once

/** For struct pollfd */
#include <poll.h>

/* For QString, QThread, QTimer, etc.. */
#include <QtCore>

namespace DFL {
    namespace IPC {
        class Client;
        class ClientImpl;
    }
}

class DFL::IPC::Client : public QObject {
    Q_OBJECT;

    public:
        Client( QString sockPath, QObject *parent = nullptr );
        ~Client();

        /**
         * Connect to the server. If successful, emit connected().
         * If the server is not running (i.e. Connection refused),
         * emit serverNotRunning().
         * Returns true on successful connection, false otherwise.
         */
        bool connectToServer();

        /**
         * Wait for registered.
         * Sometimes, if there are too many connections at once,
         * the server might be backed up.
         * Wait @timeout us for the registration to be completed.
         * It @timeout is negative, the call will not timeout.
         */
        bool waitForRegistered( qint64 timeout = -1 );

        /**
         * Blocking call:
         * Send a message to the server.
         * If bytes written == msg.size(), return true; else false.
         */
        bool sendMessage( QString );

        /**
         * Blocking call:
         * Wait @timeout microseconds for a reply from server.
         * It @timeout is negative, the call will not timeout.
         */
        bool waitForReply( qint64 timeout = -1 );

        /**
         * Return the reply received after the last message, if any.
         */
        QString reply();

        /**
         * Disconnect from the server.
         * This also emits disconnected().
         */
        void disconnectFromServer();

    private:
        /** Our work-horse */
        DFL::IPC::ClientImpl *impl;

        /** Socket path */
        QString mSockPath;

        /** Socket FD */
        int mSockFD = -1;

    Q_SIGNALS:
        /** Relay the message received from the server */
        void messageReceived( QString );

        /** General socket error */
        void socketError( int );

        /** Error connecting to the socket */
        void serverNotRunning();

        /** Successfully connected to the server */
        void connected();

        /** Disconencted from the server */
        void disconnected();
};
