/*
 * Peony-Qt's Library
 *
 * Copyright (C) 2020, KylinSoft Co., Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library.  If not, see <https://www.gnu.org/licenses/>.
 *
 * Authors: Yue Lan <lanyue@kylinos.cn>
 *
 */

#include "file-launch-manager.h"
#include "file-utils.h"
#include "file-info.h"
#include "file-info-job.h"
#include <QStandardPaths>
#include "file-launch-action.h"

#include <gio/gdesktopappinfo.h>
#include <QUrl>

#include <QTimer>

using namespace Peony;

FileLaunchManager::FileLaunchManager(QObject *parent) : QObject(parent)
{

}

FileLaunchAction *FileLaunchManager::getDefaultAction(const QString &uri)
{
    //FIXME: replace BLOCKING api in ui thread.
    auto info = FileInfo::fromUri(uri);
    QString mimeType = info->mimeType();

    if (mimeType.isEmpty()) {
        FileInfoJob job(info);
        job.querySync();
        mimeType = info->mimeType();
    }

    if (info->canExecute() && info->uri().endsWith(".desktop")) {
        QUrl url = uri;
        auto path = url.path();
        GDesktopAppInfo *info = g_desktop_app_info_new_from_filename(path.toUtf8().constData());
        FileLaunchAction *action = new FileLaunchAction(uri, G_APP_INFO(info));
        g_object_unref(info);
        return action;
    } else {
        GError *error = NULL;
        GAppInfo *info  = NULL;
        /*
        * g_app_info_get_default_for_type function get wrong default app, so we get the
        * default app info from mimeapps.list, and chose the right default app for mimeType file
        */
        QString mimeAppsListPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
           + "/.config/mimeapps.list";
        GKeyFile *keyfile = g_key_file_new ();
        gboolean ret = g_key_file_load_from_file (keyfile, mimeAppsListPath.toUtf8(), G_KEY_FILE_NONE, &error);
        if (false == ret) {
            qWarning()<<"load mimeapps list error msg"<<error->message;
            info = g_app_info_get_default_for_type(mimeType.toUtf8().constData(), false);
            g_error_free(error);
        } else {
            gchar *desktopApp = g_key_file_get_string (keyfile, "Default Applications", mimeType.toUtf8(), &error);
            if (NULL != desktopApp) {
                info = (GAppInfo*)g_desktop_app_info_new(desktopApp);
                g_free (desktopApp);
            } else {
                info = g_app_info_get_default_for_type(mimeType.toUtf8().constData(), false);
            }
        }

        g_key_file_free (keyfile);

        FileLaunchAction *action = new FileLaunchAction(uri, info);
        g_object_unref(info);

        return action;
    }
}

const QList<FileLaunchAction*> FileLaunchManager::getRecommendActions(const QString &uri)
{
    //FIXME: replace BLOCKING api in ui thread.
    auto info = FileInfo::fromUri(uri);
    QString mimeType = info->mimeType();
    if (mimeType.isEmpty()) {
        FileInfoJob job(info);
        job.querySync();
        mimeType = info->mimeType();
    }
    GList *app_infos = g_app_info_get_recommended_for_type(mimeType.toUtf8().constData());
    GList *l = app_infos;
    QList<FileLaunchAction *> actions;
    while (l) {
        auto app_info = static_cast<GAppInfo*>(l->data);
        actions<<new FileLaunchAction(uri, app_info, true);
        g_object_unref(app_info);
        l = l->next;
    }
    return actions;
}

const QList<FileLaunchAction*> FileLaunchManager::getFallbackActions(const QString &uri)
{
    //FIXME: replace BLOCKING api in ui thread.
    auto info = FileInfo::fromUri(uri);
    QString mimeType = info->mimeType();
    if (mimeType.isEmpty()) {
        FileInfoJob job(info);
        job.querySync();
        mimeType = info->mimeType();
    }
    GList *app_infos = g_app_info_get_fallback_for_type(mimeType.toUtf8().constData());
    GList *l = app_infos;
    QList<FileLaunchAction *> actions;
    while (l) {
        auto app_info = static_cast<GAppInfo*>(l->data);
        actions<<new FileLaunchAction(uri, app_info, true);
        g_object_unref(app_info);
        l = l->next;
    }
    return actions;
}

const QList<FileLaunchAction*> FileLaunchManager::getAllActionsForType(const QString &uri)
{
    //FIXME: replace BLOCKING api in ui thread.
    auto info = FileInfo::fromUri(uri);
    QString mimeType = info->mimeType();
    if (mimeType.isEmpty()) {
        FileInfoJob job(info);
        job.querySync();
        mimeType = info->mimeType();
    }
    GList *app_infos = g_app_info_get_all_for_type(mimeType.toUtf8().constData());
    GList *l = app_infos;
    QList<FileLaunchAction *> actions;
    while (l) {
        auto app_info = static_cast<GAppInfo*>(l->data);
        //only show available applications
        if (g_app_info_should_show(app_info))
           actions<<new FileLaunchAction(uri, app_info, true);
        g_object_unref(app_info);
        l = l->next;
    }
    return actions;
}

const QList<FileLaunchAction*> FileLaunchManager::getAllActions(const QString &uri)
{
    GList *app_infos = g_app_info_get_all();
    GList *l = app_infos;
    QList<FileLaunchAction *> actions;
    while (l) {
        auto app_info = static_cast<GAppInfo*>(l->data);
        //only show available applications
        if (g_app_info_should_show(app_info))
           actions<<new FileLaunchAction(uri, app_info, true);
        g_object_unref(app_info);
        l = l->next;
    }
    return actions;
}

void FileLaunchManager::openSync(const QString &uri, bool forceWithArg, bool skipDialog)
{
    QString tmp = uri;
    auto targetUri = FileUtils::getTargetUri(uri);
    if (targetUri.isNull()) {
        tmp = targetUri;
    }
    auto action = getDefaultAction(tmp);
    action->lauchFileSync(forceWithArg, skipDialog);
    action->deleteLater();
}

void FileLaunchManager::openAsync(const QString &uri, bool forceWithArg, bool skipDialog)
{
    QString tmp = uri;
    //FIXME: replace BLOCKING api in ui thread.
    auto targetUri = FileUtils::getTargetUri(uri);
    if (!targetUri.isNull()) {
        tmp = targetUri;
        qDebug()<<"open async"<<targetUri;
    }
    auto action = getDefaultAction(tmp);
    action->lauchFileAsync(forceWithArg, skipDialog);
    action->deleteLater();
}

void FileLaunchManager::openAsync(const QStringList &files, bool forceWithArg, bool skipDialog)
{
    QStringList targets;
    for (auto uri : files) {
        auto target = FileUtils::getTargetUri(uri);
        if (!target.isEmpty()) {
            targets.append(target);
        } else {
            targets.append(uri);
        }
    }
    auto action = getDefaultAction(targets.first());
    action->lauchFilesAsync(targets, forceWithArg, skipDialog);
    action->deleteLater();
}

void FileLaunchManager::setDefaultLauchAction(const QString &uri, FileLaunchAction *action)
{
    //FIXME: replace BLOCKING api in ui thread.
    auto info = FileInfo::fromUri(uri);
    if (info->mimeType().isEmpty()) {
        FileInfoJob job(info);
        job.querySync();
    }

    GError *err = nullptr;
    bool ret = g_app_info_set_as_default_for_type(action->gAppInfo(),
                                       info->mimeType().toUtf8(),
                                       &err);
    if (false == ret) {
        qDebug()<<"set default app failed, err code" <<err->code <<"err msg"<< err->message;
        g_error_free(err);
    }
}
