/**
 * Copyright (c) 2022
 *    Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 *    Abrar (https://gitlab.com/s96abrar)
 *
 * DFL::NotifyWatcher is a dbus implementation of the XDG Desktop
 * Notification specifications. This class watches for the incoming
 * notification requests from the client and relays them to the
 * notification manager.
 **/

#pragma once

#include <QtCore>
#include <QtDBus>

namespace DFL {
    class NotifyWatcher;
}

class DFL::NotifyWatcher : public QDBusAbstractAdaptor {
    Q_OBJECT;
    Q_CLASSINFO( "D-Bus Interface", "org.freedesktop.Notifications" );
    Q_CLASSINFO( "D-Bus Introspection",
                 "<interface name='org.freedesktop.Notifications'>\n"
                 "    <property name='IsNotifierHostRegistered' type='b' access='read'/>\n"
                 "    <method name='RegisterNotifierHost'>\n"
                 "        <arg name='service' type='s' direction='in'/>\n"
                 "    </method>\n"
                 "    <method name='GetCapabilities'>\n"
                 "        <arg type='as' direction='out'/>\n"
                 "    </method>\n"
                 "    <method name='GetAvailableHints'>\n"
                 "        <arg type='as' direction='out'/>\n"
                 "    </method>\n"
                 "    <method name='Notify'>\n"
                 "        <annotation name='org.qtproject.QtDBus.QtTypeName.In6' value='QVariantMap'/>\n"
                 "        <arg name='name'    type='s'     direction='in'/>\n"
                 "        <arg name='id'      type='u'     direction='in'/>\n"
                 "        <arg name='icon'    type='s'     direction='in'/>\n"
                 "        <arg name='summary' type='s'     direction='in'/>\n"
                 "        <arg name='body'    type='s'     direction='in'/>\n"
                 "        <arg name='actions' type='as'    direction='in'/>\n"
                 "        <arg name='hints'   type='a{sv}' direction='in'/>\n"
                 "        <arg name='timeout' type='i'     direction='in'/>\n"
                 "        <arg type='u'     direction='out'/>\n"
                 "    </method>\n"
                 "    <method name='CloseNotification'>\n"
                 "        <arg type='u' direction='in'/>\n"
                 "    </method>\n"
                 "    <method name='GetServerInformation'>\n"
                 "        <arg type='s' direction='out'/>\n"
                 "        <arg type='s' direction='out'/>\n"
                 "        <arg type='s' direction='out'/>\n"
                 "        <arg type='s' direction='out'/>\n"
                 "    </method>\n"
                 "    <signal name='ActionInvoked'>\n"
                 "        <arg type='u' direction='out'/>\n"
                 "        <arg type='s' direction='out'/>\n"
                 "    </signal>\n"
                 "    <signal name='NotificationClosed'>\n"
                 "        <arg type='u' direction='out'/>\n"
                 "        <arg type='u' direction='out'/>\n"
                 "    </signal>\n"
                 "</interface>\n"
    );

    public:
        /** Notification struct */
        typedef struct notification_t {
            QString     appName;
            uint        id;
            QString     appIcon;
            QString     summary;
            QString     body;
            QStringList actions;
            QVariantMap hints;
            int         timeout;
        } Notification;

        NotifyWatcher( QString notifierFunction, QObject *parent );
        ~NotifyWatcher();

        /**
         * Main methods and properites
         * These slots and properties are as defined in XDG Notification Spec
         */

        /** Get the capabilities of our server */
        Q_SLOT QStringList GetCapabilities();

        /** Get the hints supported by our server */
        Q_SLOT QStringList GetAvailableHints();

        /** Create a notification */
        Q_SLOT uint Notify( QString, uint, QString, QString, QString, QStringList, QVariantMap, int );

        /** Close a notification */
        Q_SLOT void CloseNotification( uint id );

        /** Return the server information */
        Q_SLOT QString GetServerInformation( QString&, QString&, QString& );

        /** Our addition: To check if some notification manager is registered */
        Q_PROPERTY( bool IsNotifierHostRegistered READ isNotifierHostRegistered );
        bool isNotifierHostRegistered() const;

        /** Our addition: To register some notification manager */
        Q_SLOT void RegisterNotifierHost( const QString& service );

        /**
         * Extra support
         * For use with Notification Manager class
         */

        /** Set the list of allowed hints */
        void setAvailableHints( QStringList );

        /** Set the list of capabilities */
        void setCapabilities( QStringList );

        /** Set the server information: name, vendor, version, spec version */
        void setServerInformation( QStringList );

        /** Emit the ActionInvoked signal */
        Q_SLOT void emitActionInvoked( uint id, QString action );

        /** Emit the NotificationClosed signal */
        Q_SLOT void emitNotificationClosed( uint id, uint reason );

    private:
        bool registered = true;
        static QString notifyFunction;

        QStringList mCapabilities;
        QStringList mAvailableHints;
        QStringList mServerInfo;

    Q_SIGNALS:
        /** Used return the actions performed by the client */
        void ActionInvoked( uint, QString );

        /** A notification with Request ID @id was closed with reason @reason */
        void NotificationClosed( uint id, uint reason );

        /** Client requested that notification with Request ID @id be closed  */
        void CloseNotificationRequest( uint id );
};

/** Convert a DFL::NotifyWatcher::Notification from/to QDBusArgument  */
QDBusArgument &operator<<( QDBusArgument&, const DFL::NotifyWatcher::Notification& );
const QDBusArgument &operator>>( const QDBusArgument&, DFL::NotifyWatcher::Notification& );

/** Compare two DFL::NotifyWatcher::Notification objects */
bool operator==( const DFL::NotifyWatcher::Notification&, const DFL::NotifyWatcher::Notification& );

/** So that we can use it in QMetaObject::invokeMethod(...) and signals, etc. */
Q_DECLARE_METATYPE( DFL::NotifyWatcher::Notification );
