/**
 * Copyright (c) 2022
 *    Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 *    Abrar (https://gitlab.com/s96Abrar)
 *
 * The DFL::XDG namespace contains several functions that return
 * paths as per the XDG Specifications - XDG_CONFIG_DIRS
 * DFL::XDG::DesktopFile class is a desktop file parser.
 * DFL::XDG::ApplicationManager is the Mime-App manager.
 **/

#pragma once

#include <QStringList>
#include <QObject>
#include <QString>
#include <QHash>
#include <QMap>

class MimeAppsListParser;

namespace DFL {
    namespace XDG {
        QString homeDir();

        QString xdgCacheHome();
        QString xdgConfigHome();
        QString xdgDataHome();
        QString xdgStateHome();

        QStringList xdgConfigDirs();
        QStringList xdgDataDirs();

        QString xdgDesktopDir();
        QString xdgDocumentsDir();
        QString xdgDownloadDir();
        QString xdgMusicDir();
        QString xdgPicturesDir();
        QString xdgPublicshareDir();
        QString xdgTemplatesDir();
        QString xdgVideosDir();

        QString xdgRuntimeDir();

        class DesktopFile;
        class ApplicationManager;
    }
    typedef QList<DFL::XDG::DesktopFile> AppsList;
}

class DFL::XDG::DesktopFile {
    public:
        enum Type {
            Application = 0x906AF2,     // A regular executable app
            Link,                       // Linux equivalent of '.lnk'			! NOT HANDLED
            Directory                   // Desktop that points to a directory	! NOT HANDLED
        };

        DesktopFile( QString filename = QString() );        // Create an instance of a desktop file

        bool startApplication( QStringList args, QString action = QString() );

        QString desktopName() const;                  // Filename of the desktop
        QString name() const;                         // Name
        QString genericName() const;                  // Generic Name
        QString description() const;                  // Comment
        QString executable() const;                   // 'TryExec' value or the path divined from 'Exec'

        QString command() const;                      // Full command as given in 'Exec'
        QString icon() const;                         // Application Icon Name or Path
        QString category() const;                     // Main category according to XDG

        QStringList mimeTypes() const;                // MimeTypes handled by this app
        QStringList categories() const;               // Categories this app belongs to

        QStringList actions() const;                  // Actions in this app
        QStringList action( QString id ) const;       // Name, Icon, Exec list for the given action

        int type() const;                             // Application/Link/Directory
        int rank() const;                             // How important is this desktop file

        bool visible() const;                         // Visible in 'Start' Menu
        bool runInTerminal() const;                   // If this app should be run in the terminal
        bool multipleArgs() const;                    // Does the app take multiple arguments?
        bool isValid() const;                         // Is a valid desktop file

        QString desktopFileUrl() const;               // URL of the desktop file

        // Check if this DFL::XDG::DesktopFile is equivalent to @other
        bool operator==( const DFL::XDG::DesktopFile& ) const;

        QMap<QString, QStringList> mActions;

    private:
        QString mFileUrl, mDesktopName, mExec, mCommand;
        QString mName, mGenericName, mDescription, mIcon;
        QString mCategory;
        QStringList mMimeTypes, mCategories, mActionNames;

        bool mVisible, mRunInTerminal, mValid = false;
        bool mMultiArgs = false, mTakesArgs = false;

        int mType;

        short int mRank = 0;

        QString desktopPathForName( QString );
        void getCategory();
};

class DFL::XDG::ApplicationManager : public QObject {
    Q_OBJECT;

    public:
        /** Init */
        ApplicationManager();

        /** All desktops */
        DFL::AppsList allApplications();

        /** Get a list of application that can handle the given mimetype */
        QStringList appsForMimeType( QString );

        /** Default application for the given mimetype
         *  This will be read from @mimeDefaultAppHash.
         *  @mimeDefaultAppHash will be updated as and when the mimeapps.list files get updated
         */
        QString defaultAppForMimeType( QString );

        /** Set the default application for the given mimetype
         *  arg1: mimetype
         *  arg2: basename of the desktop file (ex: desq-eye.desktop)
         *
         *  The newly set association will be stored in ~/.config/mimeapps.list
         *  under the section [Default Applications]
         */
        void setDefaultAppForMimeType( QString, QString );

        /** List of paths where the desktop files are stored */
        static QStringList applicationPaths();

    private:

        /** Parse the desktops in all the folders and also
         *  populate @mimeAppsHash and @mimeDefaultAppHash
         */
        void parseDesktops();

        /** List of applications for a given mimetype
         *  The mimetypes will be added as and when the desktop files are parsed.
         *
         *  key: mimetype (ex: image/png)
         *  value: list of desktop basenames (ex: desq-eye.desktop, qimgv.desktop, gimp.desktop, ...)
         *
         *  Only valid desktops will be added to this list
         */
        QHash<QString, QStringList> mimeAppsHash;

        /** Default applications for mimetypes
         *  The mimetypes will be added from mimeapps.list
         *  Read https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html
         *
         *  key: mimetype (ex: image/png)
         *  value: desktop basename of the default app (ex: desq-eye.desktop)
         *
         *  If the desktop specified in the mimeapps.list is invalid (see DesktopFile::isValid()),
         *  Then that mimetype will not be added.
         */
        QHash<QString, QString> mimeDefaultAppHash;

        /** MimeAppsListParser for writing default files.
         *  We will write all the defaults to ~/.config/mimeapps.list
         */
        MimeAppsListParser *defaultWriter;

        /**
         * A map of all desktops
         */
        QHash<QString, DFL::XDG::DesktopFile> mAllDesktops;
};

uint qHash( const DFL::XDG::DesktopFile& app );

Q_DECLARE_METATYPE( DFL::XDG::DesktopFile );
