/**
 * Copyright Marcus Britanicus <marcusbritanicus@gmail.com>
 *
 * This file is a part of LibDesQ (https://gitlab.com/DesQ/libdesq)
 * This library contains various  Core and Gui classes which are used
 * through out the DesQ Project.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * at your option, any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 **/

#pragma once

#include "desq/Globals.hpp"

class MimeAppsListParser;

namespace DesQ {
    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<DesQ::DesktopFile> AppsList;
}

class DesQ::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(), QMap<QString, QString> environ = QMap<QString, QString>() );

        QString desktopName() const;                        // Filename of the desktop
        QString name() const;                               // Name
        QString genericName() const;                        // Generic Name
        QString description() const;                        // Comment
        QString exec() 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;

        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 DesQ::DesktopFile is equivalent to @other
        bool operator==( const DesQ::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 DesQ::ApplicationManager : public QObject {
    Q_OBJECT;

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

        /** All desktops */
        DesQ::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, DesQ::DesktopFile> mAllDesktops;
};

uint qHash( const DesQ::DesktopFile& app );

Q_DECLARE_METATYPE( DesQ::DesktopFile );
