#ifndef MPRISDBUSCLIENT_H
#define MPRISDBUSCLIENT_H

#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include <QDebug>

/*
 * Common mpris interface，reference：https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html
 */
class MPRISDBusClient : public QDBusAbstractInterface
{
    Q_OBJECT

public:
    MPRISDBusClient(
        const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);

    ~MPRISDBusClient();

    Q_PROPERTY(QString PlaybackStatus READ playbackStatus NOTIFY PlaybackStatusChanged)
    inline QString playbackStatus() const
    {
        return qvariant_cast<QString>(property("PlaybackStatus"));
    }

    Q_PROPERTY(QString LoopStatus READ loopStatus WRITE setLoopStatus NOTIFY LoopStatusChanged)
    inline QString loopStatus() const
    {
        return qvariant_cast<QString>(property("LoopStatus"));
    }

    inline void setLoopStatus(const QString &value)
    {
        setProperty("LoopStatus", QVariant::fromValue(value));
    }

    Q_PROPERTY(double Rate READ rate WRITE setRate NOTIFY RateChanged)
    inline double rate() const
    {
        return qvariant_cast<double>(property("Rate"));
    }
    inline void setRate(double value)
    {
        setProperty("Rate", QVariant::fromValue(value));
    }

    Q_PROPERTY(bool Shuffle READ shuffle WRITE setShuffle NOTIFY ShuffleChanged)
    inline bool shuffle() const
    {
        return qvariant_cast<bool>(property("Shuffle"));
    }
    inline void setShuffle(bool value)
    {
        setProperty("Shuffle", QVariant::fromValue(value));
    }

    Q_PROPERTY(QVariantMap Metadata READ metadata NOTIFY MetadataChanged)
    inline QVariantMap metadata() const
    {
        return qvariant_cast<QVariantMap>(property("Metadata"));
    }

    Q_PROPERTY(double Volume READ volume WRITE setVolume NOTIFY VolumeChanged)
    inline double volume() const
    {
        return qvariant_cast<double>(property("Volume"));
    }
    inline void setVolume(double value)
    {
        setProperty("Volume", QVariant::fromValue(value));
    }

    Q_PROPERTY(qlonglong Position READ position NOTIFY PositionChanged)
    inline qlonglong position() const
    {
        return qvariant_cast<qlonglong>(property("Position"));
    }

    Q_PROPERTY(double MinimumRate READ minimumRate NOTIFY MinimumRateChanged)
    inline double minimumRate() const
    {
        return qvariant_cast<double>(property("MinimumRate"));
    }

    Q_PROPERTY(double MaximumRate READ maximumRate NOTIFY MaximumRateChanged)
    inline double maximumRate() const
    {
        return qvariant_cast<double>(property("MaximumRate"));
    }

    Q_PROPERTY(bool CanGoNext READ canGoNext NOTIFY CanGoNextChanged)
    inline bool canGoNext() const
    {
        return qvariant_cast<bool>(property("CanGoNext"));
    }

    Q_PROPERTY(bool CanGoPrevious READ canGoPrevious NOTIFY CanGoPreviousChanged)
    inline bool canGoPrevious() const
    {
        return qvariant_cast<bool>(property("CanGoPrevious"));
    }

    Q_PROPERTY(bool CanPlay READ canPlay NOTIFY CanPlayChanged)
    inline bool canPlay() const
    {
        return qvariant_cast<bool>(property("CanPlay"));
    }

    Q_PROPERTY(bool CanPause READ canPause NOTIFY CanPauseChanged)
    inline bool canPause() const
    {
        return qvariant_cast<bool>(property("CanPause"));
    }

    Q_PROPERTY(bool CanSeek READ canSeek NOTIFY CanSeekChanged)
    inline bool canSeek() const
    {
        return qvariant_cast<bool>(property("CanSeek"));
    }

    Q_PROPERTY(bool CanControl READ canControl NOTIFY CanControlChanged)
    inline bool canControl() const
    {
        return qvariant_cast<bool>(property("CanControl"));
    }

public Q_SLOTS: // METHODS
    void onPropertyChanged(const QDBusMessage &msg);

    inline QDBusPendingReply<> Next()
    {
        QList<QVariant> argumentList;
        qDebug()<<"media Next!!";
        return asyncCallWithArgumentList(QStringLiteral("Next"), argumentList);
    }

    inline QDBusPendingReply<> Previous()
    {
        QList<QVariant> argumentList;
        qDebug()<<"media Previous!!";
        return asyncCallWithArgumentList(QStringLiteral("Previous"), argumentList);
    }

    inline QDBusPendingReply<> Pause()
    {
        QList<QVariant> argumentList;
        qDebug()<<"media Pause!!";
        return asyncCallWithArgumentList(QStringLiteral("Pause"), argumentList);
    }

    inline QDBusPendingReply<> PlayPause()
    {
        QList<QVariant> argumentList;
        qDebug()<<"media PlayPause!!";
        return asyncCallWithArgumentList(QStringLiteral("PlayPause"), argumentList);
    }

    inline QDBusPendingReply<> Stop()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QStringLiteral("Stop"), argumentList);
    }

    inline QDBusPendingReply<> Play()
    {
        QList<QVariant> argumentList;
        qDebug()<<"media Play!!";
        return asyncCallWithArgumentList(QStringLiteral("Play"), argumentList);
    }

    inline QDBusPendingReply<> Seek(qlonglong Offset)
    {
        QList<QVariant> argumentList;
        argumentList << QVariant::fromValue(Offset);
        return asyncCallWithArgumentList(QStringLiteral("Seek"), argumentList);
    }

    inline QDBusPendingReply<> SetPosition(const QDBusObjectPath &TrackId, qlonglong Position)
    {
        QList<QVariant> argumentList;
        argumentList << QVariant::fromValue(TrackId) << QVariant::fromValue(Position);
        return asyncCallWithArgumentList(QStringLiteral("SetPosition"), argumentList);
    }

    inline QDBusPendingReply<> OpenUri(const QString &Uri)
    {
        QList<QVariant> argumentList;
        argumentList << QVariant::fromValue(Uri);
        return asyncCallWithArgumentList(QStringLiteral("OpenUri"), argumentList);
    }

Q_SIGNALS: // SIGNALS
    void Seeked(qlonglong Position);
    // begin property changed signals
    void CanControlChanged(bool value);
    void CanGoNextChanged(bool value);
    void CanGoPreviousChanged(bool value);
    void CanPauseChanged(bool value);
    void CanPlayChanged(bool value);
    void CanSeekChanged(bool value);
    void LoopStatusChanged(const QString &value);
    void MaximumRateChanged(double value);
    void MetadataChanged(const QVariantMap &value);
    void MinimumRateChanged(double value);
    void PlaybackStatusChanged(const QString &value);
    void PositionChanged(qlonglong value);
    void RateChanged(double value);
    void ShuffleChanged(bool value);
    void VolumeChanged(double value);
};

#endif // MPRISDBUSCLIENT_H
