/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * Copyright (C) 2019 KylinSoft  Co., Ltd.
 *
 * 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 2 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */
#include "autostartinterface.h"
#include <QDir>
#include <KSharedConfig>
#include <KConfigGroup>
#include <QDebug>

#include "../../universalinterface.h"

#define LOCAL_CONFIG_DIR           "/.config/autostart/"
#define SYSTEM_CONFIG_DIR          "/etc/xdg/autostart/"
#define USR_CONFIG_DIR             "/usr/share/applications/"
#define UKCC_AUTOAPP_KEY           "autoapp-list"

AutoStartInterface::AutoStartInterface(QObject *parent) : UKUI::ServiceObject(parent)
{
    mUkccGsettings = UniversalInterface::self()->ukccGsettings();
    mStyleGsettings = UniversalInterface::self()->ukuiStyleGsettings();

    if (mUkccGsettings)
        connect(mUkccGsettings, &QGSettings::changed, [=](const QString &key){
            emit changed(key);
        });
    if (mStyleGsettings)
        connect(mStyleGsettings, &QGSettings::changed, [=](const QString &key){
            emit changed(key);
        });

    whiteList.append("sogouImeService.desktop");
    whiteList.append("kylin-weather.desktop");
    mSysServiceMap = getServiceMap();
    mAllAppMap = getAllAppMap();
}

AutoApp AutoStartInterface::getAppInfo(const QString &filepath)
{
    AutoApp app;
    QFileInfo file = QFileInfo(filepath);
    QString mainSection = "Desktop Entry";
    KSharedConfig::Ptr sharedConfig = KSharedConfig::openConfig(filepath, KConfig::NoGlobals);
    KConfigGroup cfg(sharedConfig, mainSection);
    app.bname = file.fileName();
    app.name = cfg.readEntry("Name");
    app.icon = cfg.readEntry("Icon");
    if (app.bname == "sogouImeService.desktop")
       app.icon = "/opt/sogouimebs/files/share/resources/skin/logo/logo.png";
    app.hidden = cfg.readEntry("Hidden", false);
    return app;
}

QStringList AutoStartInterface::getAppList()
{
    QStringList list;
    if (mUkccGsettings->keys().contains("autoappList"))
        list = mUkccGsettings->get(UKCC_AUTOAPP_KEY).toStringList();
    return list;
}

QMap <QString, QVariant> AutoStartInterface::getStatusMap()
{
    QMap <QString, QVariant> map;
    for (QMap<QString, AutoApp>::iterator it = mAllAppMap.begin(); it != mAllAppMap.end(); it++)
        map.insert(it.key(), QVariant::fromValue(it.value()));
    return map;
}

QMap <QString , AutoApp> AutoStartInterface::getLocalAppMap()
{
    QDir localdir(QString(QDir::homePath()+LOCAL_CONFIG_DIR).toUtf8());
    QDir usrdir(QString(USR_CONFIG_DIR).toUtf8());
    QStringList filters;
    filters<<QString("*.desktop");
    localdir.setFilter(QDir::Files | QDir::NoSymLinks);
    localdir.setNameFilters(filters);

    QMap <QString , AutoApp> map;

    QStringList usrlist;
    for(uint i = 0 ; i < usrdir.count() ; i++)
        usrlist.append(usrdir[i]);

    for (uint i = 0; i < localdir.count(); i++) {
        QString file_name = localdir[i];  // 文件名称
        if (!usrlist.contains(file_name) && !whiteList.contains(file_name)) {
            QFile::remove(QString(QDir::homePath() + LOCAL_CONFIG_DIR + file_name));
            continue;
        }
        AutoApp app;
        app = getAppInfo(QDir::homePath()+LOCAL_CONFIG_DIR+file_name);
        app.position = Pos::LOCALPOS;
        map.insert(app.bname, app);
    }
    return map;

}

QMap <QString , AutoApp> AutoStartInterface::getServiceMap()
{
    qDBusRegisterMetaType<AutoApp>();
    QDir systemdir(QString(SYSTEM_CONFIG_DIR).toUtf8());
    QStringList filters;
    filters<<QString("*.desktop");
    systemdir.setFilter(QDir::Files | QDir::NoSymLinks);
    systemdir.setNameFilters(filters);
    QMap <QString , AutoApp> map;
    for( QString file_name : whiteList) {
        AutoApp app;
        if (!QFile(SYSTEM_CONFIG_DIR+file_name).exists() && file_name == "kylin-weather.desktop")
            file_name = "indicator-china-weather.desktop";;
        app = getAppInfo(SYSTEM_CONFIG_DIR + file_name);
        if (app.name.isEmpty())
            continue;
        app.position = Pos::SYSTEMPOS;
        map.insert(app.bname, app);
    }
    return map;
}

QMap<QString, AutoApp> AutoStartInterface::getAllAppMap()
{
    QMap<QString, AutoApp> map;
    QMap<QString, AutoApp>::iterator it = mSysServiceMap.begin();
    for (; it != mSysServiceMap.end(); it++) {
        map.insert(it.key(), it.value());
    }

    QMap<QString, AutoApp> localMap = getLocalAppMap();
    QMap<QString, AutoApp>::iterator localit = localMap.begin();
    for (; localit != localMap.end(); localit++) {
        if (map.contains(localit.key())) {
            QMap<QString, AutoApp>::iterator updateit = map.find(localit.key());
            updateit.value().hidden = false;
        } else {
            map.insert(localit.key(), localit.value());
        }
    }
    return map;
}

bool AutoStartInterface::deleteLocalFile(const QString &filename)
{
    QString dstpath = QDir::homePath() + LOCAL_CONFIG_DIR + filename;
    if (filename.isEmpty() || !QDir().exists(dstpath))
        return false;

    QMap<QString, AutoApp>::iterator updateit = mAllAppMap.find(filename);
    if (updateit == mAllAppMap.end())
         qCritical() << "mAllAppMap Data Error when delete local file";
    else {
        if (updateit.value().position == LOCALPOS) {
            mAllAppMap.remove(filename);
        } else {
            updateit.value().hidden = true;
        }
    }

    if (QFile::remove(dstpath))
        return true;
    return false;

}

bool AutoStartInterface::copyFiletoLocal(const QString &filename)
{
    QString srcPath;
    QString dstPath;

    QMap<QString, AutoApp>::iterator it = mSysServiceMap.find(filename);
    if (it == mSysServiceMap.end()) {
        srcPath = USR_CONFIG_DIR + filename;
    } else {
        srcPath = SYSTEM_CONFIG_DIR + filename;
    }

    dstPath = QDir::homePath() + LOCAL_CONFIG_DIR + filename;

    if (!QFile::copy(srcPath, dstPath))
        return false;

    //将复制的文件权限改为可读写
    QFile(dstPath).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);

    it = mAllAppMap.find(filename);
    if (it == mAllAppMap.end()) {
        AutoApp app = getAppInfo(srcPath);
        app.position = Pos::LOCALPOS;
        mAllAppMap[filename] = app;
    }
    return true;
}

bool AutoStartInterface::setAppHiddenInfo(const QString &filename, bool hidden)
{
    QString dstpath = QDir::homePath() + LOCAL_CONFIG_DIR + filename;
    if (filename.isEmpty() || !QDir().exists(dstpath))
        return false;

    QString mainSection = "Desktop Entry";
    KSharedConfig::Ptr sharedConfig = KSharedConfig::openConfig(dstpath, KConfig::NoGlobals);
    KConfigGroup cfg(sharedConfig, mainSection);
    cfg.writeEntry("Hidden", hidden);
    QMap<QString, AutoApp>::iterator updateit = mAllAppMap.find(filename);
    if (updateit != mAllAppMap.end())
        updateit.value().hidden = hidden;
    return true;
}

bool AutoStartInterface::addAutobootApp(const QString &filename)
{
    AutoApp app = getAppInfo(filename);
    app.position = Pos::LOCALPOS;

    QMap<QString, AutoApp>::iterator it = mAllAppMap.begin();
    for (; it != mAllAppMap.end(); it++) {
        if (it.value().name == app.name) {
            return false;
        }
    }

    if (!copyFiletoLocal(app.bname)) {
        qCritical() << "add autobootApp failed";
        return false;
    }
    return true;
}

bool AutoStartInterface::saveAppStatus(const QString &filename, bool status)
{
    QMap<QString, AutoApp>::iterator it = mAllAppMap.find(filename);
    if (it == mAllAppMap.end()) {
        return false;
    }
    if (status) { // 开启开机启动
        it.value().hidden = false;
        if (it.value().position == SYSTEMPOS) { // 从~/.config/autostart目录下删除
            deleteLocalFile(filename);
        } else {// 改值("hidden"字段->false)
            setAppHiddenInfo(filename, false);
        }
    } else { // 关闭
        if (it.value().position == SYSTEMPOS) { // 复制后改值，将对应应用的desktop文件从/etc/xdg/autostart目录下复制到~/.config/autostart目录下
            if (copyFiletoLocal(filename)) {
                setAppHiddenInfo(filename, true);
                it.value().hidden = true;
            }
        } else {// 改值
            setAppHiddenInfo(filename, true);
            it.value().hidden = true;
        }
    }
    return true;
}

bool AutoStartInterface::setApplist(const QStringList &list)
{
    if (mUkccGsettings->keys().contains("autoappList"))
        mUkccGsettings->set(UKCC_AUTOAPP_KEY, list);
    return true;
}

bool AutoStartInterface::getDisplayStatus(const QString &filename)
{
    QString mainSection = "Desktop Entry";
    KSharedConfig::Ptr sharedConfig = KSharedConfig::openConfig(filename, KConfig::NoGlobals);
    KConfigGroup cfg(sharedConfig, mainSection);
    return cfg.readEntry("NoDisplay", false);
}

const QDBusArgument &operator<<(QDBusArgument &argument, const AutoApp &app)
{
    argument.beginStructure();
    argument << app.bname;
    argument << app.icon;
    argument << app.name;
    argument << app.hidden;
    argument << app.position;
    argument.endStructure();
    return argument;
}

const QDBusArgument &operator>>(const QDBusArgument &argument, AutoApp &app)
{
    argument.beginStructure();
    argument >> app.bname;
    argument >> app.icon;
    argument >> app.name;
    argument >> app.hidden;
    argument >> app.position;
    argument.endStructure();
    return argument;
}
