#ifndef _TenkinetPanel_h__
#define _TenkinetPanel_h__

#include <QGridLayout>
#include <QHash>
#include <QLabel>
#include <QLineEdit>
#include <QMap>
#include <QMovie>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
#include <QVector>
#include <QWidget>

#include "LogConversionDialog.h"
#include "TenkinetProvider.h"
#include "TenkinetProviderBox.h"

class TenkinetPanel : public QWidget {

    friend class TenkinetProviderBox;

    Q_OBJECT

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

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

    virtual ~TenkinetPanel();

  signals:
    void localProviderRefreshed();

  public slots:

    void start();
    void shutdown();
    void setLocked(bool locked);
    void refreshLocalProvider();

  private slots:

    void addProvider(const QString &host, const QString &port);
    void addProvider(TenkinetProvider *provider);
    void removeProvider(TenkinetProvider *provider);

    void onClickAdd();
    void onClickDiscover();
    void onClickConvertLog();

    void onDiscoveryInit();
    void onDiscoveryError(int error);
    void onDiscoveryStart();
    void onDiscoveryEnd();
    void refreshDiscoveryMovie();

    void onProviderConnecting(TenkinetProvider *provider);
    void onProviderConnected(TenkinetProvider *provider);
    void onProviderDisconnected(TenkinetProvider *provider);
    void onProviderError(TenkinetProvider *provider);
    void onProviderRefreshing(TenkinetProvider *provider);
    void onProviderRefreshed(TenkinetProvider *provider);
    void onProviderEnabled(TenkinetProvider *provider);
    void onProviderDisabled(TenkinetProvider *provider);

    void onTimerTick();

  private:
    TenkinetPanel();

    // Layouts and widgets

    QVBoxLayout *devicesLayout;
    QVector<TenkinetProviderBox *> boxes;
    QLabel *lockedLabel;
    QLineEdit *hostEdit;
    QPushButton *addButton;
    QPushButton *discoverButton;
    QMovie *discoverMovie;
    QIcon *discoverIcon;
    QIcon *discoverErrorIcon;
    LogConversionDialog *logConversionDialog;

    // State

    bool locked = false;
    bool discoveryRunning = false;

    // Providers

    QVector<TenkinetProvider *> providers;
    QHash<QString, TenkinetProvider *> providerMap;
    QHash<TenkinetProvider *, TenkinetProviderBox *> providerBoxMap;

    TenkinetProvider *localProvider = nullptr;

    // Reconnection logic

    struct Counter {
        int n;
        Counter(int n) : n(n) {}
    };

    QTimer timer;
    QMap<TenkinetProvider *, Counter *> reconnectionCountdown;
};

#endif
