#ifndef _TDeviceManager_h__
#define _TDeviceManager_h__

#include <QHash>
#include <QList>
#include <QMap>
#include <QMutex>
#include <QObject>
#include <QVector>

#include "TDeviceSignal.h"
#include "TProvider.h"
#include "WatchdogListener.h"
#include "queue.h"

/**
 * Singleton class
 */
class TDeviceManager : public QObject {

    Q_OBJECT

  public:
    // Singleton instance
    static TDeviceManager &instance() {
        static TDeviceManager instance;
        return instance;
    }

    // Disable copy constructor and assignment operator
    // Required to enforce singleton pattern
    TDeviceManager(TDeviceManager const &) = delete;
    void operator=(TDeviceManager const &) = delete;

    virtual ~TDeviceManager();

    QVector<TDevice *> getDevices();
    TDevice *getDevice(const QString &serialNumber);
    TDeviceSignal *getDeviceSignal(const QString &serialNumber);
    TChannel *getChannel(const QString &id);
    QString getAlias(const QString &id);

  public slots:

    void setChannelAlias(QString id, QString alias);

    void addWatchdogListener(WatchdogListener *listener);
    void removeWatchdogListener(WatchdogListener *listener);

    void addDevice(const TDevice *device);
    void removeDevice(const TDevice *device);
    void connectDevice(const TDevice *device);
    void disconnectDevice(const TDevice *device);
    void updateDevice(const TDevice *device);

  private:
    TDeviceManager();

    void addEvent(TDevice::Event code, const TDevice *device);
    bool onDeviceAdded(TDevice *device);
    bool onDeviceUpdated(TDevice *device);

    void watchdog(int64_t timestamp);

    QMutex mutex;
    Queue events;
    size_t loadFactor;
    size_t previousLoadFactor;
    float previousLoadPerSecond;
    int64_t watchdogInterval;
    int64_t watchdogTimestamp;
    QVector<WatchdogListener *> watchdogListeners;
    QMap<QString, TDevice *> devicesBySerialNumber;
    QHash<QString, TDeviceSignal *> signalsBySerialNumber;
    QHash<QString, TChannel *> channelsByID;
    QHash<QString, QString> aliasesByID;

  private slots:

    void onEvent();

  signals:

    void __event__();

    void deviceAdded(const TDevice *device);
    void deviceRemoved(const TDevice *device);
    void channelAliasUpdated(const QString id, const QString alias);
};

#endif
