#ifndef _TenkinetProvider_h__
#define _TenkinetProvider_h__

#include <QHash>
#include <QMutex>
#include <QSettings>
#include <QVector>

#include "TProvider.h"

#include "device.h"
#include "list.h"

class TenkinetThread;

class TenkinetProvider : public TProvider {

    friend class TenkinetThread;

    Q_OBJECT

  public:
    enum State {
        DISCONNECTED,
        CONNECTING,
        CONNECTED,
        BROKEN,
    };

    static const QString DEFAULT_SERVER_PORT;

    TenkinetProvider(const QString &host, const QString &port);
    virtual ~TenkinetProvider();

    virtual int getDeviceCount();
    virtual QVector<TDevice *> getDevices();
    virtual TDevice *findDevice(const QString &serialNumber);

    const QString &getServerHost();
    const QString &getServerPort();
    const QString &getServerHostAndPort();

    QString getServerAddress();
    QString getServerAddressAndPort();
    QString getServerSerialNumber();
    QString getServerName();
    Version getServerVersion();
    uint64_t getPing();

    State getState();
    bool isFavorite();
    bool isEnabled();

    virtual int start();
    virtual void shutdown();

    virtual void setPollInterval(int ms);
    virtual void setVirtualOptions(unsigned int flags, double slp);
    virtual void setUserCalibration(const QString &serialNumber, int channelIndex, bool on);

    void setFavorite(bool favorite);
    void setEnabled(bool enabled);

    void setServerAddress(const QString &address);
    void setServerSerialNumber(const QString &serialNumber);
    void setServerName(const QString &name);
    void setServerVersion(const Version &version);

    void refresh();

  signals:

    void connecting(TenkinetProvider *provider);
    void connected(TenkinetProvider *provider);
    void disconnected(TenkinetProvider *provider);
    void error(TenkinetProvider *provider);
    void refreshing(TenkinetProvider *provider);
    void refreshed(TenkinetProvider *provider);
    void enabled(TenkinetProvider *provider);
    void disabled(TenkinetProvider *provider);

  private:
    const QString host;
    const QString port;
    const QString hostAndPort;
    const QString settingsKey;

    QString address;
    QString serialNumber;
    QString name;
    Version version;

    uint64_t ping;
    QMap<QString, TDevice *> devicesBySerialNumber;
    QMap<QString, Source *> sourcesBySerialNumber;

    State state = DISCONNECTED;
    bool favorite;
    bool on;

    QMutex mutex;

  private: // Used by TenkinetThread
    void *handle = nullptr;

    void onConnect();
    void onDisconnect();
    void onError();
    void onList(List *tenkinetDevices);
    void onData(int64_t timestamp, List *tenkinetDevices);
    void onDeviceConnect(int64_t timestamp, Device *tenkinetDevice);
    void onDeviceDisconnect(int64_t timestamp, Device *tenkinetDevice);
    void onPing(uint64_t ping);

    TDevice *updateDevice(int64_t timestamp, Device *tenkinetDevice);
};

#endif
