/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef STREAMUNLIMITEDDEVICE_H
#define STREAMUNLIMITEDDEVICE_H

#include <QObject>
#include <QHostAddress>
#include <QUuid>
#include <QNetworkReply>

#include <types/browseritem.h>
#include <types/mediabrowseritem.h>

class NetworkAccessManager;

class StreamUnlimitedSetRequest;

class StreamUnlimitedDevice : public QObject
{
    Q_OBJECT
public:
    enum ConnectionStatus {
        ConnectionStatusDisconnected,
        ConnectionStatusConnecting,
        ConnectionStatusConnected
    };
    Q_ENUM(ConnectionStatus)


    enum PlayStatus {
        PlayStatusStopped,
        PlayStatusPlaying,
        PlayStatusPaused
    };
    Q_ENUM(PlayStatus)

    enum Repeat {
        RepeatNone,
        RepeatOne,
        RepeatAll
    };
    Q_ENUM(Repeat)

    explicit StreamUnlimitedDevice(NetworkAccessManager *nam, const QHash<QString, QUuid> idMap, const QString &uiPath, QObject *parent = nullptr);
    virtual ~StreamUnlimitedDevice() = default;

    void addSubscriptions(const QStringList &subscriptions);

    void setHost(const QHostAddress &address, int port);
    QHostAddress address() const;
    int port() const;

    ConnectionStatus connectionStatus();

    QString deviceVersion() const;

    QLocale language() const;

    PlayStatus playbackStatus() const;
    uint duration();
    uint playTime();

    virtual uint volume() const;
    virtual QUuid setVolume(uint volume);

    bool mute() const;
    QUuid setMute(bool mute);

    bool shuffle() const;
    QUuid setShuffle(bool shuffle);

    Repeat repeat() const;
    QUuid setRepeat(Repeat repeat);

    QString title() const;
    QString artist() const;
    QString album() const;
    QString artwork() const;

    bool canPause() const;
    QUuid play();
    QUuid pause();
    QUuid stop();
    QUuid skipBack();
    QUuid skipNext();

    QUuid setPlayTime(uint playTime);

    QUuid notification(const QUrl &soundUrl);

    QUuid browseDevice(const QString &itemId);
    QUuid playBrowserItem(const QString &itemId);
    QUuid browserItem(const QString &itemId);
    virtual QUuid executeContextMenu(const QString &itemId, const ActionTypeId &actionTypeId);

    QUuid setLocaleOnBoard(const QLocale &locale);

    QUuid storePreset(uint presetId);
    QUuid loadPreset(uint presetId);

    bool power() const;
    QUuid setPower(bool power);

signals:
    void connectionStatusChanged(ConnectionStatus status);
    void commandCompleted(const QUuid &commandId, bool success);

    void playbackStatusChanged(PlayStatus status);
    void durationChanged(quint64 duration);
    void playTimeChanged(quint64 playTime);
    void volumeChanged(uint volume);
    void muteChanged(bool mute);

    void titleChanged(const QString &title);
    void artistChanged(const QString &artist);
    void albumChanged(const QString &album);
    void artworkChanged(const QString &artwork);

    void favoriteChanged(bool favorite);

    void shuffleChanged(bool shuffle);
    void repeatChanged(Repeat repeat);

    void canPauseChanged(bool canPause);

    void powerChanged(bool power);

    void browseResults(const QUuid &commandId, bool success, const BrowserItems &items = BrowserItems());
    void browserItemResult(const QUuid &commandId, bool success, const BrowserItem &item = BrowserItem());

    void changeNotification(const QString &path);
    void playerDataChanged(const QVariantMap &playerData);

private:
    void pollQueue();
    void reconnectSoon();

    void fetchVersion();
    void refreshPlayerData();
    void refreshVolume();
    void refreshMute();
    void refreshPlayMode();
    void refreshPlayTime();
    void refreshLanguage();
    void refreshPower();

    StreamUnlimitedSetRequest* setPlayMode(bool shuffle, Repeat repeat);
    QUuid executeControlCommand(const QString &command);

    QUuid browseInternal(const QString &itemId, const QUuid &commandIdOverride = QUuid());

protected:
    NetworkAccessManager *m_nam = nullptr;
    QHostAddress m_address;
    int m_port = 80;

private:
    QNetworkReply *m_pollReply = nullptr;

    QString m_deviceVersion;

    // FIXME: this should be determined by the stream sdk version but I couldn't find reliable version info on the api
    QString m_uiPath = "ui:";

    ConnectionStatus m_connectionStatus = ConnectionStatusDisconnected;
    QUuid m_pollQueueId;

    PlayStatus m_playbackStatus = PlayStatusStopped;
    uint m_volume = 0;
    bool m_mute = false;
    QString m_title;
    QString m_artist;
    QString m_album;
    QString m_artwork;
    quint64 m_playTime = 0;
    quint64 m_duration = 0;
    bool m_canPause = false;

    bool m_shuffle = false;
    Repeat m_repeat = RepeatNone;
    bool m_power = false;

    QLocale m_language;

    QUuid m_playFirstBrowseResult;

    QStringList m_additionalSubscriptions;

    QHash<QString, QUuid> m_ids;
};

#endif // STREAMUNLIMITEDDEVICE_H
