#include "tabletdesktopbackend.h"
#include "appnamesort.h"
#include <QString>
#include <KDesktopFile>
#include <KConfigGroup>
#include <QFileInfo>
#include <QEventLoop>
#include <QLocale>
#include <QCoreApplication>
#include <QTranslator>
#include <QDir>
#include <QDBusConnection>
#include <QDebug>
#include <QDBusInterface>
#include <QDBusPendingCall>
#include <QDBusReply>
#include <QPair>
#include "ukuisettings.h"

const char *desktop_dir = "/usr/share/applications/";
// static int LeftIconSize = 19; //图标大小
const char *TABLET_LAUNCHER_SCHEMA = "org.kylin-tablet-desktop";
const char *TABLET_LAUNCHER_PATH = "/org/kylin-tablet-desktop/";

namespace UKUI {

TabletDesktopBackend::TabletDesktopBackend():
    m_idlePosPage(-2), m_appListener(nullptr),m_Filewatcher(nullptr)
    , m_maxPage(0), m_loadCount(0), m_notEmptyDir(1)
    , m_panelSettings(nullptr), isFirstStart(false)

{
    qRegisterMetaType<appChangeInfo>("appChangeInfo");

    QTranslator *translator = new QTranslator(this);

    if(translator->load("/usr/share/ukui/translations/ukui-tablet-desktop/zh_CN.qm")) {
        QCoreApplication::installTranslator(translator);
    } else {
        qDebug() << "翻译文件加载失败！";
    }

    // const QByteArray &schema_id, const QByteArray &path = QByteArray(), QObject *parent = NULL
    QByteArray id(TABLET_LAUNCHER_SCHEMA);
    if (QGSettings::isSchemaInstalled(id)) {
        m_tabletLauncher = new QGSettings(id, QByteArray(TABLET_LAUNCHER_PATH));
        m_line = m_tabletLauncher->get("line").toUInt();
        m_column = m_tabletLauncher->get("column").toUInt();
        isFirstStart = m_tabletLauncher->get("isFirstStart").toBool();
        if(isFirstStart) {
            qDebug() << "kylin tablet desktop is started firstly ! ! !";
            m_tabletLauncher->set("isFirstStart", QVariant(false));
        }
    } else {
        m_line = 4;
        m_column = 6;
    }

    QString dbPath = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/appList.db";
    if ( !QFile::exists(dbPath) ) {
        qDebug() << "kylin tablet desktop is started firstly ! ! !";
        isFirstStart = true;    // 当手动将数据库删除时，也认定为是第一次启动
    }
    m_icon_theme = IconTheme::getInstance();

    loadPositions();
    desktopFileWatcher();
    panelConfFileWatcher();
    // 等待数据遍历完成后再继续初始化数据
    QEventLoop loop;
    connect(this, &TabletDesktopBackend::firstTraversalCompleted, &loop, &QEventLoop::quit);
    loop.exec();
    // 获取数据库中的所有被删除应用的 id，要将这部分应用从数据库中删除
    // 防止在桌面崩溃后，用户通过其他手段将应用删除，此时检测是为了及时更新数据库
    checkIfDatabaseExistDeletedApp();
    monitorIconThemeChange();

    // 加载任务栏的应用数据，如果有变化的话，同步更改到数据库
    loadTaskBarData();

    if (m_database->getFirstInit()) {
        createDefaultGroup();
        updatePageData();
    }
    QDBusConnection::systemBus().connect(QString("com.kylin.systemupgrade"),
                                         QString("/com/kylin/systemupgrade"),
                                         QString("com.kylin.systemupgrade.interface"),
                                         QString("PurgePackagesFinished"), this, SLOT(appUninstallComplete(bool, QString)));

}
TabletDesktopBackend::~TabletDesktopBackend()
{
    if (m_baseItemList.size() > 0) {
        for (int i = 0; i < m_baseItemList.size(); i++) {
            delete m_baseItemList[i];
        }
    }
    if (m_appListener) {
        m_appListener->deleteLater();
        m_appListener = nullptr;
    }
    if (m_Filewatcher) {
        m_Filewatcher->deleteLater();
        m_Filewatcher = nullptr;
    }
    if (m_database) {
        m_database->deleteLater();
        m_database = nullptr;
    }
    if (m_icon_theme) {
        m_icon_theme->deleteLater();
        m_icon_theme = nullptr;
    }
    if (m_tabletLauncher) {
        m_tabletLauncher->deleteLater();
        m_tabletLauncher = nullptr;
    }
    if (m_panelSettings) {
        m_panelSettings->deleteLater();
        m_panelSettings = nullptr;
    }
    if (m_widgetSettings) {
        m_widgetSettings->deleteLater();
        m_widgetSettings = nullptr;
    }
    if (m_appWidgetManager) {
        m_appWidgetManager->deleteLater();
        m_appWidgetManager = nullptr;
    }
}

void TabletDesktopBackend::loadPositions()
{
    m_database = new DataBase(this);

    if (!m_database->openDatabase()) {
        qDebug() << "openDatabase 打开数据库失败";
    }

    if (m_database->getFirstInit()) {
        m_appWidgetManager = new AppWidget::KAppWidgetManager(this);
        createWidgetData();
    }

    m_baseItemList = m_database->queryAllItemData();
    allPage = m_database->queryAllPageData();
    allFlipSets = m_database->queryAllFlipSetData();
    allScrollSets = m_database->queryAllScrollSetData();
    for (int page = 0; page < allPage.size(); page++) {
        m_allItemList += allPage[allPage.keys().at(page)];
        if (page > m_maxPage)
            m_maxPage = page;
    }
    for (int i = 0; i < allFlipSets.size(); i++) {
        QList<QList<quint32>> appListList = allFlipSets[allFlipSets.keys().at(i)];
        for (int j = 0; j < appListList.size(); j++)
            m_allItemList += appListList[j];
    }
    for (int i = 0; i < allScrollSets.size(); i++) {
        m_allItemList += allScrollSets[allScrollSets.keys().at(i)];
    }
    // 更新第一个空闲位置的 Item 所在的页数
    updateExistIdlePage();
}

void TabletDesktopBackend::loadTaskBarData()
{
    // 获取任务栏的应用列表
    QList<quint32> taskBarAppData;
    if (isFirstStart) {
        if (QFile::exists(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf")) {
            m_panelSettings = new Settings(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf", QSettings::IniFormat, "taskbar");
            if (m_panelSettings) {
                QList<QMap<QString, QVariant> > taskBarApp = m_panelSettings->readArray("apps");
                for (int var = 0; var < taskBarApp.size(); ++var) {
                    quint32 taskbarAppId = getAppIdAccordingString(taskBarApp[var]["desktop"].toString());
                    if (taskbarAppId != 0) {
                        qDebug() << taskBarApp[var]["desktop"].toString() << taskbarAppId;
                        taskBarAppData.append(taskbarAppId);
                    }
                }
            }
        } else if (QFile::exists("/usr/share/ukui/panel.conf")) {
            m_panelSettings = new Settings("/usr/share/ukui/panel.conf", QSettings::IniFormat, "taskbar");
            if (m_panelSettings) {
                QList<QMap<QString, QVariant> > taskBarApp = m_panelSettings->readArray("apps");
                for (int var = 0; var < taskBarApp.size(); ++var) {
                    quint32 taskbarAppId = getAppIdAccordingString(taskBarApp[var]["desktop"].toString());
                    if (taskbarAppId != 0) {
                        qDebug() << taskBarApp[var]["desktop"].toString() << taskbarAppId;
                        taskBarAppData.append(taskbarAppId);
                    }
                }
            }
        } else {
            quint32 taskbarAppId;
            taskbarAppId = getAppIdAccordingString("/usr/share/applications/peony.desktop");
            if (taskbarAppId != 0)
                taskBarAppData.append(taskbarAppId);
            taskbarAppId = getAppIdAccordingString("/usr/share/applications/kylin-software-center.desktop");
            if (taskbarAppId != 0)
                taskBarAppData.append(taskbarAppId);
            taskbarAppId = getAppIdAccordingString("/usr/share/applications/wps-office-wps.desktop");
            if (taskbarAppId != 0)
                taskBarAppData.append(taskbarAppId);
        }

        if (m_database->querySetDataFromID(0).length() == 0) {
            m_database->addScrollSet(0, taskBarAppData);
        } else {
            m_database->setScrollSetData(0, taskBarAppData);
        }
        allScrollSets[0] = taskBarAppData;

        qDebug() << "为了防止page页里有重复的id，需要将任务栏的应用从page页移除";
        removeTaskbarItemFromPage();

        qDebug() << "将任务栏的应用从page页移除后需要将前面page页的空白位置补齐";
        updateExistIdlePage();
        fillUpIdlePosition();

        for (int pageId = allPage.size() - 1; pageId >= 0; --pageId) {
            // 由于移动应用产生空白页，则删除
            if (allPage[pageId].size() == 0) {
                allPage.remove(pageId);
                if (!m_database->deletePageData(pageId)) {
                    qWarning() << __func__ << " 删除页数据失败";
                    return;
                }
            }
        }
    } else if (QFile::exists(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf")) {
        m_panelSettings = new Settings(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf", QSettings::IniFormat, "taskbar");
        if (m_panelSettings) {
            QList<QMap<QString, QVariant> > taskBarApp = m_panelSettings->readArray("apps");
            for (int var = 0; var < taskBarApp.size(); ++var) {
                quint32 taskbarAppId = getAppIdAccordingString(taskBarApp[var]["desktop"].toString());
                qDebug() << taskBarApp[var]["desktop"].toString() << taskbarAppId;
                taskBarAppData.append(taskbarAppId);
            }
        }
        if (taskBarAppData != allScrollSets[0])
            taskBarAppChange(taskBarAppData);
    }
}

void TabletDesktopBackend::monitorIconThemeChange()
{
    connect(m_icon_theme, &IconTheme::iconThemeChanged, [=](){
        for (int i = 0; i < m_baseItemList.size(); i++) {
            quint32 id = m_baseItemList.keys().at(i);
            if (Type::Icon == m_baseItemList[id]->getType()) {
                IconItem *appItem = static_cast<IconItem *>(m_baseItemList[id]);
                QString absoluteDesktopName = appItem->getDesktopName();

                const KDesktopFile desktopFile(absoluteDesktopName);
                QString iconName = desktopFile.readIcon();

                QString absoluteIconName = getAbsoluteIconPath(iconName, 96);
                appItem->setIconName(absoluteIconName);
            }
        }
        emit iconThemeChanged();
    });
    emit iconThemeChanged();
}

void TabletDesktopBackend::desktopFileWatcher()
{
    // 先获取到所有的应用列表，然后通过遍历所有系统中的desktop文件，存在系统中的应用则从此列表删除
    // 绝大多数情况，遍历完所有desktop文件后，删除列表应该为空
    // 但是也要防止在PC模式删除了一些应用，但是平板桌面插件还没有加载，这时候就会有一部分应用的删除监测不到
    m_shoudBeRemovedApp = m_baseItemList.keys();
    QList<quint32>::iterator pos = m_shoudBeRemovedApp.begin();
    while (pos != m_shoudBeRemovedApp.end()) {
        if (m_baseItemList[*pos]->getType() == Type::Icon) {
            pos++;
        } else {
            pos = m_shoudBeRemovedApp.erase(pos);
        }
    }
    m_appListener = new KDirLister(this);

    if (!m_database->checkTablesData()) {
        qDebug() << "checkTablesData 检查修正表数据出现异常";
    }

    // 启动平板桌面后台时，会遍历一遍所有的desktop文件
    connect(m_appListener, &KCoreDirLister::itemsAdded, this, &TabletDesktopBackend::onItemsAdded);
    connect(m_appListener, &KCoreDirLister::itemsDeleted, this, &TabletDesktopBackend::onItemsDeleted);

    m_appListener->openUrl(QUrl::fromUserInput(QString(desktop_dir)), KDirLister::OpenUrlFlag::Keep);
    QDir android_path(QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)[0]);
    if(android_path.exists()) {
        m_appListener->openUrl(QUrl::fromUserInput(QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)[0]), KDirLister::OpenUrlFlag::Keep);
        if (!android_path.isEmpty()) {
            m_notEmptyDir++;
        }
    }
    m_appListener->setAutoUpdate(true);
    m_appListener->started(QUrl::fromUserInput(QString(desktop_dir)));
}

void TabletDesktopBackend::panelConfFileWatcher()
{
     m_Filewatcher = new QFileSystemWatcher(this);
     m_Filewatcher->addPath(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf");
     connect(m_Filewatcher, SIGNAL(fileChanged(const QString &)), this, SLOT(taskBarAppChange()));
}

void TabletDesktopBackend::addLauncherPage(int page)
{
    m_maxPage = page;
    m_idlePosPage = m_maxPage;
    QList<quint32> itemList;
    allPage[m_idlePosPage] = itemList;
    if (!m_database->addPage(m_idlePosPage, itemList)) {
        qWarning() << "添加 page 数据失败" << __func__;
    }
}

void TabletDesktopBackend::deleteLauncherPage(int page)
{
    qDebug() << "kylinTabletDesktopBackend::deleteLauncherPage(int page)" << page << m_maxPage;
    for (quint32 j = page; j < m_maxPage; ++j) {
        // 将 page 页后面的 itemList 以此前移
        QList<quint32> item_list = allPage[j+1];
        if (!setPageData(j, item_list)) {
            qWarning() << __func__ << "修改page页数据失败";
            return;
        }
    }
    // 删除最后一页，因为最后一页的内容已经拷贝到上一页
    allPage.remove(m_maxPage);
    if (!m_database->deletePageData(m_maxPage)) {
        qWarning() << __func__ << " 删除页数据失败";
        return;
    }
    m_maxPage--;
}

void TabletDesktopBackend::removeLauncherItem(quint32 id)
{
    qDebug() << "kylinTabletDesktopBackend::removeLauncherItem(quint32 id)" << id;
    // 1. 从内存 m_allItemList 列表里删除该 id
    m_allItemList.removeOne(id);

    // 2. 从数据库 itemList 删除
    if (!m_database->deleteItemListData(id)) {
        qWarning() << "从列表中删除应用失败" << __func__;
        return;
    }

    // warning，注意防止内存泄露
    delete m_baseItemList[id];
    if (m_baseItemList.remove(id) != 1)
        qDebug() << "移除 item" << "id" << "失败！";

    // 3. 检查 sets 数据库，是否存在删除的 item（不用考虑 set 全部为空的情况，但是FlipSet某一子页为空时，需要删除此子页）
    removeItemFromSet(id);

    // 4. 从 allPage 数据库删除该 item（需要考虑 page 为空, 然后删除空白 page 页的情况）
    for (int pageId = 0; pageId < allPage.size(); pageId++) {
        QList<quint32> &itemlist = allPage[pageId];
        if(itemlist.indexOf(id) >= 0) {
            itemlist.removeAt(itemlist.indexOf(id));
            if(itemlist.size() == 0) {
                emit itemDeletedFromPage(id, pageId);
            } else {
                setPageData(pageId, itemlist);
                emit itemDeletedFromPage(id, pageId);
            }
            break;
        }
    }
}

void TabletDesktopBackend::removeItemFromSet(quint32 id)
{
    int key;
    for (int i = 0; i < allScrollSets.size(); i++) {
        key = allScrollSets.keys().at(i); // key值为set的id
        QList<quint32> all_scrollSetValue = allScrollSets[key];
        int scrollSetValueId = all_scrollSetValue.indexOf(id);
        if(scrollSetValueId >= 0) {
            all_scrollSetValue.removeAt(scrollSetValueId);
            setScrollSetData(key, all_scrollSetValue);
            qDebug() << "emit itemDeletedFromScorllSet(id, key)" << id << key;
            emit itemDeletedFromSet(id, key);
            return;
        }
    }
    for (int i = 0; i < allFlipSets.size(); i++) {
        bool removeFlipSet = false;
        key = allFlipSets.keys().at(i); // key值为set的id
        QList<QList<quint32>> flipSetValue = allFlipSets[key];
        for (int page = 0; page < flipSetValue.size(); page++) {
            QList<quint32> &setPageValue = flipSetValue[page];
            int setPageValueId = setPageValue.indexOf(id);
            if (setPageValueId >= 0) {
                setPageValue.removeAt(setPageValueId);
                if (page < flipSetValue.count()-1 && flipSetValue[page+1].count() > 0) {
                    quint32 fillUpId = flipSetValue[page+1].takeFirst();
                    if (flipSetValue[page+1].count() == 0) {
                        flipSetValue.removeAt(page+1);
                    }
                    setPageValue.push_back(fillUpId);
                    qDebug() << "分组非最后一页卸载应用，后一页应用向前补齐";
                }
                removeFlipSet = true;
                if (setPageValue.empty()) {
                    flipSetValue.removeOne(setPageValue);
                    if (flipSetValue.empty()) {
                        allFlipSets.remove(key);
                        break;
                    }
                }
            }           
        }
        if (removeFlipSet) {
            setFlipSetData(key, flipSetValue);
            emit itemDeletedFromSet(id, key);
            qDebug() << "emit itemDeletedFromFlipSet(id, key)" << id << key;
            return;
        }
    }
}

quint32 TabletDesktopBackend::getAppIdAccordingString(const QString desktopName)
{
    QMap<quint32, BaseItem *>::iterator i = m_baseItemList.begin();
    while (i != m_baseItemList.end()) {
        if (i.value()->getType() == Type::Icon) {
            IconItem *app = static_cast<IconItem *>(i.value());
            if (app->getDesktopName() == desktopName)
                return i.key();
        }
        ++i;
    }
    return 0;
}

QStringList TabletDesktopBackend::getBlackListApp()
{
    QStringList blackList;
    blackList << "software-properties-livepatch.desktop"
              << "mate-color-select.desktop"
              << "blueman-adapters.desktop"
              << "mate-user-guide.desktop"
              << "nm-connection-editor.desktop"
              << "debian-uxterm.desktop"
              << "debian-xterm.desktop"
              << "im-config.desktop"
              << "fcitx.desktop"
              << "fcitx-configtool.desktop"
              << "onboard-settings.desktop"
              << "info.desktop"
              << "ukui-power-preferences.desktop"
              << "ukui-power-statistics.desktop"
              << "software-properties-drivers.desktop"
              << "software-properties-gtk.desktop"
              << "gnome-session-properties.desktop"
              << "org.gnome.font-viewer.desktop"
              << "xdiagnose.desktop"
              << "gnome-language-selector.desktop"
              << "mate-notification-properties.desktop"
              << "transmission-gtk.desktop"
              << "mpv.desktop"
              << "system-config-printer.desktop"
              << "org.gnome.DejaDup.desktop"
              << "yelp.desktop"
                 //v10
              << "mate-about.desktop"
              << "time.desktop"
              << "network.desktop"
              << "shares.desktop"
              << "mate-power-statistics.desktop"
              << "display-im6.desktop"
              << "display-im6.q16.desktop"
              << "openjdk-8-policytool.desktop"
              << "kylin-io-monitor.desktop"
              << "wps-office-uninstall.desktop"
              << "wps-office-misc.desktop"
              << "kylin-installer.desktop";
    return blackList;
}

QList<int> TabletDesktopBackend::matchingAppCategories(QString category)
{
    // copy from ukui-menu master
    QVector<QStringList> vector;
    vector.append(QStringList() << "Android");              // 0安卓
    vector.append(QStringList() << "Network");              // 1网络
    vector.append(QStringList() << "Messaging");            // 2社交
    vector.append(QStringList() << "Audio" << "Video");     // 3影音
    vector.append(QStringList() << "Development");          // 4开发
    vector.append(QStringList() << "Graphics");             // 5图像
    vector.append(QStringList() << "Game");                 // 6游戏
    vector.append(QStringList()
                  << "Office" << "Calculator"
                  << "Spreadsheet" << "Presentation"
                  << "WordProcessor" << "TextEditor");      // 7办公
    vector.append(QStringList() << "Education");            // 8教育
    vector.append(QStringList()
                  << "System"
                  << "Settings"
                  << "Security");                           // 9系统


    QList<int> itemCategories;
    bool findCategory = false;
    for (int j = 0; j < vector.count(); j++) {
        for (int i = 0; i < vector.at(j).count(); i++) {
            if (category.contains(vector[j].at(i), Qt::CaseInsensitive)) {
                itemCategories.append(j);
                findCategory = true;
                break;
            }
        }
    }
    if (!findCategory) {
        itemCategories.append(vector.size());
    }
    return itemCategories;
}

QList<quint32> TabletDesktopBackend::sortAppIdAccordingLetter(QList<quint32> &unorderedIdList)
{
    QMap<AppNameSort, quint32> orderedApp;
    foreach (auto &id, unorderedIdList) {
        if (m_baseItemList[id]->getType() == Type::Icon && !m_baseItemList[id]->getName().isEmpty()) {
            QString appName = m_baseItemList[id]->getName();
            orderedApp[AppNameSort(appName)] = id;
        }
    }
    return orderedApp.values();
}

void TabletDesktopBackend::checkIfDatabaseExistDeletedApp()
{
    qDebug() << "需要删除的数据库应用为 m_shoudBeRemovedApp: " << m_shoudBeRemovedApp;
    foreach (quint32 id, m_shoudBeRemovedApp) {
        removeLauncherItem(id);
    }
}

QString TabletDesktopBackend::getAbsoluteIconPath(QString iconName, quint32 size)
{
    QFileInfo iconFileInfo(iconName);
    QString absoluteIconPath;
    if (iconFileInfo.isFile() && (iconName.endsWith(".png") || iconName.endsWith(".svg") || iconName.endsWith(".ico"))) {
        return iconName;
    } else {
        iconName.remove(".png");
        iconName.remove(".svg");
        iconName.remove(".ico");
        absoluteIconPath = m_icon_theme->getPathFromName(iconName, size);

        if (absoluteIconPath.isEmpty()) {
            if (QFile::exists(QString("/usr/share/icons/hicolor/scalable/apps/%1.%2").arg(iconName).arg("svg"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/scalable/apps/%1.%2").arg(iconName).arg("svg");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/96x96/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/96x96/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/64x64/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/64x64/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/48x48/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/48x48/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/16x16/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/16x16/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/96x96/mimetypes/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/96x96/mimetypes/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/64x64/mimetypes/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/64x64/mimetypes/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/48x48/mimetypes/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/48x48/mimetypes/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/hicolor/16x16/mimetypes/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/hicolor/16x16/mimetypes/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/gnome/48x48/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/gnome/48x48/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/icons/gnome/32x32/apps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/icons/gnome/32x32/apps/%1.%2").arg(iconName).arg("png");
            } else if (QFile::exists(QString("/usr/share/pixmaps/%1.%2").arg(iconName).arg("svg"))) {
                absoluteIconPath = QString("/usr/share/pixmaps/%1.%2").arg(iconName).arg("svg");
            } else if (QFile::exists(QString("/usr/share/pixmaps/%1.%2").arg(iconName).arg("png"))) {
                absoluteIconPath = QString("/usr/share/pixmaps/%1.%2").arg(iconName).arg("png");
            } else {
                absoluteIconPath = m_icon_theme->getPathFromName("application-x-desktop", size);
            }
        }
    }
    return absoluteIconPath;
}

QMap<Categories, QString> TabletDesktopBackend::getAllAppCategories() {
    QMap<Categories, QString> categoriesInfo;
    categoriesInfo[Categories::Android] = tr("Mobile");
    categoriesInfo[Categories::Network] = tr("Internet");
    categoriesInfo[Categories::Messaging] = tr("Social");
    categoriesInfo[Categories::Audio] = tr("Video");
    categoriesInfo[Categories::Development] = tr("Development");
    categoriesInfo[Categories::Graphics] = tr("Image");
    categoriesInfo[Categories::Game] = tr("Game");
    categoriesInfo[Categories::Office] = tr("Office");
    categoriesInfo[Categories::Education] = tr("Education");
    categoriesInfo[Categories::System] = tr("System");
    categoriesInfo[Categories::Other] = tr("Others");
    return categoriesInfo;
}

QList<quint32> TabletDesktopBackend::getAppIdListAccordingCategory(Categories type)
{
    QList<quint32> appIdList;
    QList<quint32> allItemId = m_baseItemList.keys();
    QList<BaseItem *> allItemInfo = m_baseItemList.values();
    for (int i = 0; i < m_baseItemList.size(); i++) {
        if (allItemInfo.at(i)) {
            QList<int> categories = allItemInfo.at(i)->getCategories();
            if (categories.contains(static_cast<int32_t>(type)))
                appIdList.append(allItemId.at(i));
        }
    }
    return sortAppIdAccordingLetter(appIdList);
}

QList<quint32> TabletDesktopBackend::getAllAppIdList()
{
    QList<quint32> appIdList;
    QList<quint32> allItemId = m_baseItemList.keys();
    for (int i = 0; i < m_baseItemList.size(); i++) {
        if (m_baseItemList[allItemId[i]] && (m_baseItemList[allItemId[i]]->getType() == Type::Icon) )
            appIdList.append(allItemId[i]);
    }
    return sortAppIdAccordingLetter(appIdList);
}

void TabletDesktopBackend::onItemsAdded(const QUrl &directoryUrl, const KFileItemList &items)
{
    Q_UNUSED(directoryUrl)
    QStringList blackAppList = getBlackListApp();
    for (const KFileItem &fileItem : items) {
        if (!fileItem.isDesktopFile()) {
            continue;
        }
        if (!fileItem.url().toString().endsWith("desktop")) {
            continue;
        }

        QString desktopName = fileItem.name();
        QString absoluteDesktopName = fileItem.url().path();
        const KDesktopFile desktopFile(absoluteDesktopName);
        KConfigGroup desktopGroup =  desktopFile.desktopGroup();
        // 如果代码里没有写NoDisplay=false，desktopFile.noDisplay()返回的值也是true，所以不能用desktopFile.noDisplay()进行判断
        // 有些desktop写的是NoDisplay=true;多了一个分号，所以要用contains判断
        if (desktopGroup.readEntry("NoDisplay").contains("true") || desktopFile.readIcon().isEmpty() || !desktopFile.hasApplicationType()) {
            continue;
        }
        if (blackAppList.contains(desktopName)) {
            continue;
        }

        QString iconName = desktopFile.readIcon();
        // appName 会随着系统语言的切换自动修改为当前使用的语言的名字
        QString appName = desktopFile.readName();
        QString appType = desktopFile.readType();
        QString execPath = desktopGroup.readEntry("Exec");
        QString appCategories = desktopGroup.readEntry("Categories");
        QString absoluteIconName = getAbsoluteIconPath(iconName, 96);
        QList<int> actualCategories = matchingAppCategories(appCategories);

        Q_UNUSED(appType)
        Q_UNUSED(execPath)

        bool isFindIcon = false;
        for (int i = 0; i < m_baseItemList.size(); i++) {
            quint32 id = m_baseItemList.keys().at(i);
            if (m_baseItemList[id] && (Type::Icon == m_baseItemList[id]->getType())) {
                IconItem *appItem = static_cast<IconItem *>(m_baseItemList[id]);
                if (appItem->getDesktopName() == absoluteDesktopName) {
                    // 更新为当前语言的名字
                    if (appItem->getName() != appName || appItem->getCategories() != actualCategories || appItem->getIconName() != absoluteIconName) {
                        appItem->setName(appName);
                        appItem->setCategories(actualCategories);
                        appItem->setIconName(absoluteIconName);
                        m_database->modifyItemData(appItem->getId(), absoluteDesktopName, appName, absoluteIconName, actualCategories);
                    }
                    isFindIcon = true;
                    // 检测到系统存在该应用，将该应用从删除列表中移除
                    m_shoudBeRemovedApp.removeOne(appItem->getId());
                    break;
                }
            }
        }

        if (isFindIcon)
            continue;
        int idleNumber = updateExistIdlePage();  // 更新第一个空闲位置的 Item 所在的页数

        qDebug() << __FUNCTION__ << "m_idlePosPage: " << m_idlePosPage
                 << "m_maxPage:" << m_maxPage
                 << "updateExistIdlePage()" << idleNumber;
        if (m_idlePosPage == -2) {   // 说明所有页已经填充满
            addLauncherPage(m_maxPage + 1);
        }

        // 将应用添加到 item 列表数据库
        // 数据库存储的应用图标是绝对路径的图标
        m_database->addItem(getIdleItemID(), absoluteDesktopName, appName, absoluteIconName, static_cast<int32_t>(Type::Icon), {1,1}, actualCategories);

        quint32 id = m_database->queryIdFromDesktopName(absoluteDesktopName);
        // 如果该id已经存在page或者set里，就不再重复加入
        // 因为可能会在数据库提前插入一些预制的 id 进 page 或者 set
        if (!m_allItemList.contains(id)){
            // 添加到 page 列表数据库
            QList<quint32> itemList;
            if (m_database->getFirstInit() && m_idlePosPage < m_itemGridStatus.count()) {
                calculateItemPosition(id, m_idlePosPage);
                itemList = gridPageData(m_idlePosPage);
            } else {
                itemList = allPage[m_idlePosPage];
                itemList.append(id);
            }
            allPage[m_idlePosPage] = itemList;
            m_database->setPageData(m_idlePosPage, itemList);
            m_allItemList.append(id);
        }

        BaseItem *baseItem = new UKUI::IconItem(absoluteDesktopName, appName, id, absoluteIconName, actualCategories);
        m_baseItemList[id] = baseItem;
        emit itemAdded(id, m_idlePosPage);
        qDebug() << "添加 item id 成功！";
    }

    m_loadCount ++;
    if (m_loadCount == m_notEmptyDir) {
        emit firstTraversalCompleted();
    }
}

void TabletDesktopBackend::onItemsDeleted(const KFileItemList &items)
{
    qDebug() << __func__ << items.size();
    for (const KFileItem &fileItem : items) {
        if (!fileItem.isDesktopFile()) {
            continue;
        }
        if (!fileItem.url().toString().endsWith("desktop")) {
            continue;
        }

        QString absoluteDesktopName = fileItem.url().path();
        bool isFindIcon = false;
        quint32 id = 0;
        for (int i = 0; i < m_baseItemList.size(); i++) {
            id = m_baseItemList.keys().at(i);
            if (Type::Icon == m_baseItemList[id]->getType()) {
                IconItem *appItem = static_cast<IconItem *>(m_baseItemList[id]);
                if (appItem->getDesktopName() == absoluteDesktopName) {
                    isFindIcon = true;
                    break;
                }
            }
        }
        if (!isFindIcon) {
            return;
        }
        if (!m_uninstallAppList.contains(absoluteDesktopName) && m_allItemList.contains(id)) {
            qDebug() << "--------------保存卸载应用列表中没有找到，是通过终端卸载的应用-------" << absoluteDesktopName << m_uninstallAppList;
            removeLauncherItem(id);
            updateExistIdlePage();
        } else {
            qDebug() << "--------------保存卸载应用列表中找到了卸载完成的应用---------------" << absoluteDesktopName << m_uninstallAppList;
        }
    }
}

quint32 TabletDesktopBackend::updateExistIdlePage()
{
    m_idlePosPage = -2;
    for (quint32 page = 0; page < allPage.size(); page++) {
        quint32 sum = 0;
        QList<quint32>::iterator pageItem = allPage[page].begin();
        while (pageItem != allPage[page].end()) {
            quint32 itemId = *pageItem;
            BaseItem *item;
            if (m_baseItemList.find(itemId) != m_baseItemList.end()) {
                item = m_baseItemList[itemId];
                pageItem ++;
            } else {
                if (!m_database->updatePageItem()) {
                    qWarning() << __func__ << "删除page中不存在于itemlist的id失败";
                    return 0;
                }
                pageItem = allPage[page].erase(pageItem);
                continue;
            }
            sum += item->getPlaceHolder().at(0) * item->getPlaceHolder().at(1);
        }

        if (sum < m_line * m_column) {
            m_idlePosPage = page;
            qDebug() << "\tSum:" << sum << "Page:" << page << "Size:" << allPage[page].size() << "m_idlePosPage:" << m_idlePosPage;
            return m_line * m_column - sum;
        }
//        qDebug() << "\tSum:" << sum << "Page:" << page << "Size:" << allPage[page].size() << "m_idlePosPage:" << m_idlePosPage;
    }
    return 0;
}

quint32 TabletDesktopBackend::getIdleItemID()
{
    if (m_database) {
        return m_database->getIdleItemID();
    } else {
        return 0;
    }
}

void TabletDesktopBackend::createGroup(quint32 groupId, QList<quint32> itemIdList, const QString groupName, bool scrollable)
{
    if (itemIdList.count() < 2) {
        qWarning() << __func__ << "应用数量小于2";
        return;
    }
    QString name;
    if (groupName.size() == 0) {
        QList<int> categoryList;
        QMap<Categories, QString> categoriesInfo = getAllAppCategories();
        qDebug() << " m_baseItemList number is : " << m_baseItemList.count() << "itemIdList[1] is :" << itemIdList[1];
        if (m_baseItemList.find(itemIdList[1]) != m_baseItemList.end()) {
            categoryList = m_baseItemList[itemIdList[1]]->getCategories();
            name = categoriesInfo[Categories(categoryList.at(0))];
        } else {
            qDebug() << "m_baseItemList not find itemIdList[1] , Array out of bounds, use default name";
            name = categoriesInfo[Categories::System];
        }
    } else {
        name = groupName;
    }
    //    // 新建 group 分组的 item
    //    quint32 groupId = m_database->getIdleItemID();
    m_database->addItem(groupId, "none", name, "none", 2).toUInt();
    m_baseItemList[groupId] = new UKUI::GroupItem(name, groupId);
    m_allItemList.append(groupId);
    if (scrollable) {
        m_database->addScrollSet(groupId, itemIdList);
        allScrollSets[groupId] = itemIdList;
    } else {
        QList<QList<quint32>> list;
        list.append(itemIdList);
        m_database->addFlipSet(groupId, list);
        allFlipSets[groupId] = list;
    }
    return;
}

void TabletDesktopBackend::deleteGroup(quint32 setId)
{
    if (setId == 0) {
        return ;
    }
    if (!m_database->deleteSetsData(setId)) {
        qWarning() << "从列表中删除应用失败" << __func__;
        return;
    }
    if (allFlipSets.contains(setId)) {
        allFlipSets.remove(setId);
    }
    if (!m_database->deleteItemListData(setId)) {
        qWarning() << "删除分组数据失败" << __func__;
        return;
    }
    if (m_allItemList.contains(setId)) {
        m_allItemList.removeOne(setId);
    }
    if (m_baseItemList.contains(setId)) {
        delete m_baseItemList[setId];
        if (m_baseItemList.remove(setId) != 1) {
            qWarning() << __func__ << "移除m_baseItemList的item" << "id" << "失败！";
        }
    }
    m_database->updatePageItem();
}

void TabletDesktopBackend::uninsatllApp(const QString &desktopFile)
{
    m_uninstallAppList.append(desktopFile);
    if (!m_uninstallAppList.empty() && m_uninstallFirstApp) {
        qDebug() << __func__ << "后台开始卸载第一个应用" << m_uninstallAppList[0];
        doUninstallApp(m_uninstallAppList[0]);
        m_uninstallFirstApp = false;
    }
}

QString TabletDesktopBackend::getPkgNameByDesktop(const QString &desktopFile)
{
    std::string packName = "dpkg -S " + desktopFile.toStdString();
    char nameBuff[100] = "";
    FILE* fp = popen(packName.c_str(),"r");
    fgets(nameBuff, 100, fp);
    pclose(fp);
    std::string pkgInfo = nameBuff;
    if (pkgInfo.empty()) {
        qDebug()<<"---pkgInfo.isEmpty()---";
    }
    std::string pkg = std::string(pkgInfo.begin(), pkgInfo.begin() + pkgInfo.find(':'));
    QString pkgName = QString::fromStdString(pkg);
    qDebug() << "通过desktop获取包名" << pkgName;
    return pkgName;
}

void TabletDesktopBackend::doUninstallApp(const QString &desktopFile)
{
    m_uninstallAppDesktopname = desktopFile;
    // 区分apt安装或者apk安装方式分别调用各自的卸载接口
    qDebug() << "TabletDesktopBackend" << __FUNCTION__ << desktopFile;
    QSettings desktop(desktopFile, QSettings::IniFormat);
    QString desktopCmd = desktop.value("Desktop Entry/Exec").toString();
    // kmre应用卸载
    if (desktopCmd.contains("/usr/bin/startapp")) {
        qDebug() << "kmre应用卸载";
        if (!QDBusConnection::sessionBus().isConnected()) {
            qWarning()<< "Cannot connect to the cn.kylinos.Kmre.Manager D-Bus sessionBus.";
            return;
        }
        //调用系统cn.kylinos.Kmre.Manager服务
        QDBusInterface apkRemoveFace("cn.kylinos.Kmre.Manager",
                             "/cn/kylinos/Kmre/Manager",
                             "cn.kylinos.Kmre.Manager",
                             QDBusConnection::sessionBus());
        if (apkRemoveFace.isValid()) {
            qDebug()<< "apkRemoveFace is valid";
            QStringList strList = desktopCmd.split(" ");
            apkRemoveFace.asyncCall("uninstallApp", strList.at(1));
        } else {
            qWarning()<< "apkRemoveFace 无法调用到PurgePackages方法";
        }
    } else {
        qDebug() << "apt应用卸载";
        if (!QDBusConnection::systemBus().isConnected()) {
            qWarning()<< "Cannot connect to the  com.kylin.systemupgrade D-Bus systemBus.";
            return;
        }
        //调用系统com.kylin.systemupgrade服务
        QDBusInterface aptRemoveFace("com.kylin.systemupgrade",
                             "/com/kylin/systemupgrade",
                             "com.kylin.systemupgrade.interface",
                             QDBusConnection::systemBus());

        if (aptRemoveFace.isValid()) {
            QString pkgName = getPkgNameByDesktop(desktopFile);
            qDebug()<< "卸载包名" << pkgName;
            QStringList purgeList;
            purgeList.append(pkgName);

            QString m_userName = qgetenv("USER");
            qDebug() << "1---userName---" << m_userName;
            if (m_userName.isEmpty()){
                m_userName = qgetenv("USERNAME");
                qDebug() << "2---userName---" << m_userName;
            }
            aptRemoveFace.asyncCall("PurgePackages", purgeList, m_userName);
        } else {
            qWarning()<<"aptRemoveFace 无法调用到PurgePackages方法";
        }
    }
}

QList<quint32> TabletDesktopBackend::readPanelConf()
{
    QList<quint32> taskBarAppData;
    QString fileName(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf");
    // 如果通过vim或者编辑器修改无法监听到变化，所以必须将之前的QSettings析构掉，再重新new一个。
    if (m_panelSettings) {
        delete m_panelSettings;
        m_panelSettings = nullptr;
    }
    if (QFile::exists(fileName))
        m_panelSettings = new Settings(fileName, QSettings::IniFormat, "taskbar");

    if (m_panelSettings) {
        QList<QMap<QString, QVariant> > taskBarApp = m_panelSettings->readArray("apps");
        for (int var = 0; var < taskBarApp.size(); ++var) {
            quint32 taskbarAppId = getAppIdAccordingString(taskBarApp[var]["desktop"].toString());
            qDebug() << taskBarApp[var]["desktop"].toString() << taskbarAppId;
            taskBarAppData.append(taskbarAppId);
        }
        qDebug() << __func__ << __LINE__ << taskBarAppData;
    }
    return taskBarAppData;
}

bool TabletDesktopBackend::isListExistRepeatId(const QList<quint32> &itemIdList)
{
    QList<quint32> itemIdListSort = itemIdList;
    qSort(itemIdListSort.begin(), itemIdListSort.end());
    for (int i = 0; i < itemIdListSort.count() - 1; i++) {
        if (itemIdListSort[i] == itemIdListSort[i+1]) {
            return true;
        }
    }
    return false;
}

bool TabletDesktopBackend::isListAllIdCurrent(const QList<quint32> &itemIdList)
{
    for (int i = 0; i < itemIdList.count(); i++) {
        if (itemIdList[i] < 0) {
            return false;
        }
    }
    return true;
}

void TabletDesktopBackend::removeTaskbarItemFromPage()
{
    // 为了防止page页里有重复的id，需要将任务栏的应用从page页移除
    for (int var = 0; var < allScrollSets[0].size(); ++var) {
        // 从 allPage 数据库删除该 item
        for (int pageId = 0; pageId < allPage.size(); pageId++) {
            int id = allScrollSets[0][var];
            QList<quint32> &itemlist = allPage[pageId];
            if (itemlist.indexOf(id) >= 0) {
                itemlist.removeAt(itemlist.indexOf(id));
                if (itemlist.size() == 0) {
                    deleteLauncherPage(pageId);
                } else {
                    setPageData(pageId, itemlist);
                }
                break;
            }
        }
    }
}

void TabletDesktopBackend::fillUpIdlePosition()
{
    for (quint32 pageId = m_idlePosPage; pageId < allPage.size();) {
        if (pageId != allPage.size() - 1) {
            quint32 nextPageId = pageId + 1;
            quint32 idleNum = updateExistIdlePage();
            QList<quint32> &currentPage = allPage[pageId];
            QList<quint32> &nextPage = allPage[nextPageId];
            quint32 i = 0;
            int j = 0; // 非应用的数量-因为可能存在分组
            // TODO: 当下一页仅剩一个分组，且当前页未填充满时，无法再从下一页移动应用填充满当前页。
            while (i < idleNum && j < nextPage.size()) {
                if (m_baseItemList[nextPage[j]]->getType() == Type::Icon) {
                    currentPage.append(nextPage[j]);
                    nextPage.removeAt(j);
                    ++i;
                } else {
                    ++j;
                }
            }
            if (i != idleNum && j == 0) {
                // 前面的页没有被补全，且下一页不存在分组。
                // 说明下一页已经为空了，也没有把上一页补全。
                // 删除下一页，并继续向前补全。
                m_database->setPageData(pageId, currentPage);
                qDebug() << "dsadasdasdasd";
                deleteLauncherPage(nextPageId);
                continue;
            }
            // 1. 前一页没有补全，但是下一页是分组，不再向前补齐；
            // 2. 前一页已经补全；
            m_database->setPageData(pageId, currentPage);
            if (nextPage.size() == 0) {
                deleteLauncherPage(nextPageId);
            } else {
                m_database->setPageData(pageId+1, nextPage);
            }
            ++pageId;
        } else {
            if (allPage[pageId].size() == 0) {
                deleteLauncherPage(pageId);
            } else {
                m_database->setPageData(pageId, allPage[pageId]);
            }
            ++pageId;
        }
    }
}

void TabletDesktopBackend::taskBarAppChange()
{
    m_Filewatcher->addPath(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)[0] + "/ukui/panel.conf");
    qDebug() << "任务栏配置文件发生改变！" << __FUNCTION__;

    QList<quint32> taskBarAppData;
    taskBarAppData = readPanelConf();
    if (allScrollSets[0] == taskBarAppData)
        return;

    appChangeInfo appChangePositionData;
    bool isExchange = true;
    qDebug() << "原本任务栏列表为：" << allScrollSets[0] <<"新的任务栏列表为:" << taskBarAppData;
    // 固定应用到任务栏
    for (int i = 0; i < taskBarAppData.size(); i++) {
        if ((!allScrollSets[0].contains(taskBarAppData.at(i)))) {
            qDebug() << "固定应用到任务栏";
            isExchange = false;
            appChangePositionData.isDesktopDeleteApp = true;
            appChangePositionData.isTaskbarDeleteApp = false;
            appChangePositionData.isExchangePosition = false;
            appChangePositionData.itemId = taskBarAppData.at(i);
            //查询当前itemid 对应的页数
            for (int j = 0; j < allPage.size(); j++) {
                if (allPage[j].indexOf(taskBarAppData.at(i)) != -1) {
                    //计算出应用位于当前什么页的什么位置
                    appChangePositionData.itemFromPage = j;
                    appChangePositionData.itemFromPageIndex = allPage[j].indexOf(taskBarAppData.at(i));
                    appChangePositionData.itemToPage = 0;
                    appChangePositionData.itemToPageIndex = i;
                    break;
                }
            }

            appChangePositionData.itemToSet = 0;
            appChangePositionData.itemFromSet = -1;

            QList<quint32> &itemlist = allPage[appChangePositionData.itemFromPage];
            itemlist.removeAll(appChangePositionData.itemId);
            if(itemlist.size() == 0) {
                for (quint32 j = appChangePositionData.itemFromPage; j < m_maxPage; ++j) {
                    // 将 page 页后面的 itemList 依次前移
                    QList<quint32> item_list = allPage[j+1];
                    setPageData(j, item_list);
                }
                // 删除最后一页，因为最后一页的内容已经拷贝到上一页
                allPage.remove(m_maxPage);
                if (!m_database->deletePageData(m_maxPage)) {
                    qWarning() << __func__ << " 删除页数据失败";
                    return;
                }
                m_maxPage--;
                updateExistIdlePage();
            }
            emit taskBarAppChanged(appChangePositionData);
        }
    }

    // 从任务栏取消应用的固定
    // warning: 后台发给前台的的位置移动信号是一个一个发送的，相应的前台也是一个一个处理移动信号的。
    //          所以会出现的一个问题是：
    //          如果任务栏应用列表为 7 9 4 2 5，2和5从任务栏取消固定，后台会先将2的index 3发送给前台，然后前台根据index删除数据
    //          然后将5的index 4发送给前台，因为前台已经删除了2，所以前台的最大index变为了3，所以后台发给前台的index 4会导致前台索引出错。
    //
    //          解决办法：后台发送一个信号后就处理一下索引信息，跟新一下后台内存中的应用列表，下个移动信号发送处理后的index
    for (int i = 0; i < allScrollSets[0].size();) {
        if (!taskBarAppData.contains(allScrollSets[0].at(i))) {
            qDebug() << "从任务栏取消应用固定";
            isExchange = false;
            appChangePositionData.isDesktopDeleteApp = false;
            appChangePositionData.isTaskbarDeleteApp = true;
            appChangePositionData.isExchangePosition = false;
            appChangePositionData.itemId = allScrollSets[0].at(i);
            //查询空白页的空白位置
            int pageNullPosition = updateExistIdlePage();
            if (pageNullPosition != 0) {
                appChangePositionData.itemToPage = m_idlePosPage;
                appChangePositionData.itemToPageIndex = 24-pageNullPosition;
            } else {
                qDebug() << "创建页之前，页数为" << allPage.size();
                addLauncherPage(m_maxPage + 1);
                qDebug() << "创建完页之后，页数为" << m_maxPage + 1;
                appChangePositionData.itemToPage = m_idlePosPage;
                appChangePositionData.itemToPageIndex = 0;
            }

            appChangePositionData.itemFromPage = 0;
            appChangePositionData.itemFromPageIndex = i;

            appChangePositionData.itemFromSet=0;
            appChangePositionData.itemToSet=-1;

            allPage[m_idlePosPage].append(appChangePositionData.itemId);
            m_database->setPageData(m_idlePosPage, allPage[m_idlePosPage]);
            allScrollSets[0].removeAll(appChangePositionData.itemId);
            emit taskBarAppChanged(appChangePositionData);
        } else {
            ++i;
        }
    }

    //任务栏交换应用
    if(isExchange) {
        qDebug() << "进行任务栏应用的交换";
        appChangePositionData.isDesktopDeleteApp = false;
        appChangePositionData.isTaskbarDeleteApp = false;
        appChangePositionData.isExchangePosition = true;
        appChangePositionData.itemFromPage = 0;
        appChangePositionData.itemToPage = 0;
        appChangePositionData.itemFromSet=0;
        appChangePositionData.itemToSet=0;
        int m=0;
        for (m = 0; m<taskBarAppData.size(); m++) {
            if(taskBarAppData.contains(allScrollSets[0].at(m)) && allScrollSets[0].indexOf(taskBarAppData[m]) != m)
                break;
        }

        bool isFrontMove = false;
        int i=m;

        while (i+1 <taskBarAppData.size() && allScrollSets[0].at(i) == taskBarAppData[i+1]){
            i++;
        }
        if (allScrollSets[0].at(i) ==  taskBarAppData[m]) {
           isFrontMove = true;
           appChangePositionData.itemId = taskBarAppData[m];
           appChangePositionData.itemFromPageIndex = i;
           appChangePositionData.itemToPageIndex = m;
        }
        if (!isFrontMove) {
            while(i+1 <allScrollSets[0].size() && allScrollSets[0].at(i+1) == taskBarAppData[i]) {
                i++;
            }
            if(allScrollSets[0].at(m) ==  taskBarAppData[i]) {
               appChangePositionData.itemId = taskBarAppData[i];
               appChangePositionData.itemFromPageIndex = m;
               appChangePositionData.itemToPageIndex = i;
            }
        }
        emit taskBarAppChanged(appChangePositionData);
    }

    m_database->setScrollSetData(0, taskBarAppData);
    allScrollSets[0] = taskBarAppData;
}

void TabletDesktopBackend::taskBarAppChange(QList<quint32> &taskBarAppData)
{
    qDebug() << "原本任务栏列表为：" << allScrollSets[0] <<"新的任务栏列表为:" << taskBarAppData;

    // 固定应用到任务栏
    for (int i = 0; i < taskBarAppData.size(); i++) {
        if ((!allScrollSets[0].contains(taskBarAppData.at(i)))) {
            qDebug() << "固定应用到任务栏";
            //查询当前itemid 对应的页数
            for (int j = 0; j < allPage.size(); j++) {
                if (allPage[j].indexOf(taskBarAppData.at(i)) != -1) {
                    allPage[j].removeAll(taskBarAppData.at(i));
                    if (!m_database->setPageData(j, allPage[j])) {
                        qWarning() << __func__ << "修改page数据失败";
                        return;
                    }
                    if (0 == allPage[j].size())
                        deleteLauncherPage(j);
                    break;
                }
            }
        }
    }

    // 从任务栏取消应用的固定
    for (int i = 0; i < allScrollSets[0].size(); i++) {
        if (!taskBarAppData.contains(allScrollSets[0].at(i))) {
            qDebug() << "从任务栏取消应用固定";
            //查询空白页的空白位置
            int pageNullPosition = updateExistIdlePage();
            if (pageNullPosition == 0) {
                qDebug() << "创建页之前，页数为" << allPage.size();
                addLauncherPage(m_maxPage + 1);
                qDebug() << "创建完页之后，页数为" << m_maxPage + 1;
            }
            allPage[m_idlePosPage].append(allScrollSets[0].at(i));
            if (!m_database->setPageData(m_idlePosPage, allPage[m_idlePosPage])) {
                qWarning() << __func__ << "修改page数据失败";
                return;
            }
        }
    }

    if (taskBarAppData != allScrollSets[0]) {
        if (!m_database->setScrollSetData(0, taskBarAppData)) {
            qWarning() << __func__ << "修改page数据失败";
            return;
        }
        allScrollSets[0] = taskBarAppData;
    }
}

void TabletDesktopBackend::appUninstallComplete(bool state, QString unloadstate)
{
    quint32 uninstallAppId = getAppIdAccordingString(m_uninstallAppDesktopname);
    if (!m_allItemList.contains(uninstallAppId)) {
        return;
    }
    qDebug() << __func__ << state << unloadstate;
    if (state) {
        removeLauncherItem(uninstallAppId);
        updateExistIdlePage();
    } else {
        updateExistIdlePage();  // 更新第一个空闲位置的 Item 所在的页数
        if (m_idlePosPage == -2) {   // 说明所有页已经填充满
            addLauncherPage(m_maxPage + 1);
        }

        QList<quint32> &itemList = allPage[m_idlePosPage];
        itemList.append(uninstallAppId);
        m_database->setPageData(m_idlePosPage, itemList);
        emit itemAdded(uninstallAppId, m_idlePosPage);
    }
    if (!m_uninstallAppList.empty()) {
        qDebug() << m_uninstallAppList[0] << "卸载完成";
        m_uninstallAppList.removeAt(0);
    }
    if (!m_uninstallAppList.empty()) {
        qDebug() << "onItemsDeleted" << "继续卸载" << m_uninstallAppList[0];
        doUninstallApp(m_uninstallAppList[0]);
    } else {
        m_uninstallFirstApp = true;
    }
}

bool TabletDesktopBackend::setPageData(quint32 pageId, const QList<quint32> &itemIdList)
{
     qDebug() <<"set page data";
    if (itemIdList.size() == 0) {
        deleteLauncherPage(pageId);
    } else {
        if (isListExistRepeatId(itemIdList)) {
            return false;
        }
        if (!isListAllIdCurrent(itemIdList)) {
            return false;
        }

        // 当传入的 id 页不存在时，先新建 page 页
        if (!allPage.keys().contains(pageId)) {
            addLauncherPage(pageId);
        }
        if (!m_database->setPageData(pageId, itemIdList)) {
            qWarning() << __func__ << "修改page页数据失败";
            return false;
        }
    }
    allPage[pageId] = itemIdList;
    return true;
}

bool TabletDesktopBackend::setFlipSetData(quint32 setId, const QList<QList<quint32>> &itemIdList)
{
    qDebug() << __func__ << setId << itemIdList;
    if (!allFlipSets.contains(setId)) {
        return false;
    }
    if (itemIdList.count() == 0) {
        //前端已经发送Q_EMIT q->removeGroup(groupId)信号，接收到信号会调用deleteGroup，此处不用重复调用
//        if (m_baseItemList[setId]->getType() == Type::Group) {
//            deleteGroup(setId);
//        }
        if (m_baseItemList[setId]->getType() == Type::Container) {
            if (!m_database->deleteItemListData(setId)) {
                qWarning() << "删除分组数据失败" << __func__;
                return false;
            }
        }
    } else {
        for (int i = 0; i < itemIdList.count(); i++) {
            if (!isListAllIdCurrent(itemIdList[i])) {
                return false;
            }
        }
        if (!m_database->setFlipSetData(setId, itemIdList)) {
            qWarning() << __func__ << "修改flipset数据失败";
            return false;
        }
        allFlipSets[setId] = itemIdList;
    }
    return true;
}

bool TabletDesktopBackend::setScrollSetData(quint32 setId, const QList<quint32> &itemIdList)
{
    QList<quint32> itemSequence;
    for (int i=0; i < itemIdList.size(); i++) {
        if (m_database->queryItemIdFromList(itemIdList[i])) {
            itemSequence.append(itemIdList[i]);
        }
    }
    allScrollSets[setId] = itemSequence;
    if (!m_database->setScrollSetData(setId, itemSequence)) {
        qWarning() << __func__ << "修改scrollset数据失败";
        return false;
    }

    // 任务栏应用数据修改操作，写入 panel.conf 文件
    if (setId == 0) {
        QList<QMap<QString, QVariant> > hashList;

        for (int var = 0; var < itemSequence.size(); ++var) {
            QString desktopName;
            if (m_baseItemList.find(itemSequence[var]) != m_baseItemList.end()) {
                desktopName = static_cast<IconItem *>(m_baseItemList[itemSequence[var]])->getDesktopName();
            } else {
                continue;
            }

            QHash<QString, QString> m_settingsMap;
            m_settingsMap["desktop"] = desktopName;
            // 下面三行是为了向group里添加file、exec、name的键值对，但默认为空；
            // 为了和任务栏数据保持一致，不加的话就不会添加该键值对；
            m_settingsMap["file"];
            m_settingsMap["exec"];
            m_settingsMap["name"];
            QMap<QString, QVariant> map;
            QHashIterator<QString, QString> it(m_settingsMap);
            while (it.hasNext()) {
                it.next();
                map[it.key()] = it.value();
            }
            hashList << map;
        }
        m_panelSettings->setArray("apps", hashList);
    }
    return true;
}

bool TabletDesktopBackend::modifySetName(quint32 setId, QString name)
{
    if(name.isEmpty() || (m_baseItemList[setId]->getType() != Type::Container && m_baseItemList[setId]->getType() != Type::Group))
        return false;
    else {
        m_baseItemList[setId]->setName(name);
        return m_database->modifySetName(setId, name);
    }
}

void TabletDesktopBackend::createWidgetData()
{
    m_widgetSettings = new QSettings(DESKTOP_CONF_FILE, QSettings::IniFormat);
    QStringList widgetList;
    QList<quint32> setWidgetData;
    if (!m_widgetSettings) {
        qWarning() << "ukui-tablet-desktop.conf is not exits!!!";
        m_desktopRow = DESKTOP_ROW;
        m_desktopColumn = DESKTOP_COLUMN;
    } else {
        widgetList = m_widgetSettings->value("Desktop/appWidget").toStringList();
        QString desktopSizeString = m_widgetSettings->value("Desktop/layout").toString();
        QPair<int,int> desktopSizePair = fromStringToInt(desktopSizeString);
        if (desktopSizePair.first == 0 || desktopSizePair.second == 0) {
            qWarning() << "row or column is incorrect!!!" << __func__;
            m_desktopRow = DESKTOP_ROW;
            m_desktopColumn = DESKTOP_COLUMN;
        } else {
            m_desktopRow = desktopSizePair.first;
            m_desktopColumn = desktopSizePair.second;
        }
        initItemGridStatus();
        qDebug() << "desktopRow=" << m_desktopRow << "desktopColumn=" << m_desktopColumn;
    }
    for (int i = 0; i < widgetList.count(); ++i) {
        QString widgetQmlFilePath = m_appWidgetManager->getAppWidgetUiFile(widgetList[i]);
        QString widgetName = m_appWidgetManager->getAppWidgetConfig(widgetList[i], AppWidget::NAME);
        QString widgetIconName = m_appWidgetManager->getAppWidgetConfig(widgetList[i], AppWidget::PREVIEW_PATH);
        unsigned int minColumn = m_appWidgetManager->getAppWidgetConfig(widgetList[i], AppWidget::MIN_WIDTH).toInt();
        unsigned int minRow = m_appWidgetManager->getAppWidgetConfig(widgetList[i], AppWidget::MIN_HEIGHT).toInt();
        minRow = 1;
        minColumn = 2;
        int itemId = getIdleItemID();
        qDebug() << itemId << widgetQmlFilePath << widgetName << widgetIconName << minRow << minColumn;
        m_database->addItem(itemId, widgetQmlFilePath, widgetName, widgetIconName, static_cast<int32_t>(Type::Widget), {minRow,minColumn});
        calculateWidgetPosition(QPoint(minRow, minColumn), itemId);
    }
    itemGridDataToPage();
}

void TabletDesktopBackend::initItemGridStatus()
{
    QList<QList<int>> itemGrid;
    QList<int> cols;
    for (int row = 0; row < m_desktopRow; row++) {
        for (int col = 0; col < m_desktopColumn; ++col) {
            cols.append(0);
        }
        itemGrid.append(cols);
        cols.clear();
    }
    m_itemGridStatus[m_pageCount] = itemGrid;
}
void TabletDesktopBackend::calculateWidgetPosition(const QPoint &item, const int &itemId)
{
    bool findPos = false;
    while (!findPos) {
        if (m_pageCount >= m_itemGridStatus.count()) {
            qWarning() << "itemGridStatus page is incorrect" << __func__;
            return;
        }
        QList<QList<int>> itemGrid = m_itemGridStatus.value(m_pageCount);
        for (int col = 0; col < m_desktopColumn; ++col) {
            for (int row = 0; row < m_desktopRow; ++row) {
                if (itemGrid[row][col] == 0) {
                    int endRow = row + item.x() - 1;
                    int endcol = col + item.y() - 1;
                    if (endRow < m_desktopRow && endcol < m_desktopColumn) {
                        for (int itemcol = col; itemcol <= endcol; ++itemcol) {
                            for (int itemrow = row; itemrow <= endRow; ++itemrow) {
                                itemGrid[itemrow][itemcol] = itemId;
                            }
                        }
                        findPos = true;
                        m_itemGridStatus[m_pageCount] = itemGrid;
                        return;
                    }
                }
            }
        }
        if (!findPos) {
            m_pageCount++;
            initItemGridStatus();
        }
    }
}
void TabletDesktopBackend::calculateItemPosition(const int &itemId, const int &page)
{
    if (page >= m_itemGridStatus.count()) {
        qWarning() << "itemGridStatus page is incorrect" << __func__;
        return;
    }
    QList<QList<int>> itemGrid = m_itemGridStatus.value(page);
    for (int row = 0; row < m_desktopRow; ++row) {
        for (int col = 0; col < m_desktopColumn; ++col) {
            if (itemGrid[row][col] == 0) {
                itemGrid[row][col] = itemId;
                m_itemGridStatus[page] = itemGrid;
                return;
            }
        }
    }
}

void TabletDesktopBackend::itemGridDataToPage()
{
    int page = 0;
    while (page <= m_pageCount) {
        QList<QList<int>> itemGrid = m_itemGridStatus.value(page);
        QList<quint32> pageData;
        for (int row = 0; row < m_desktopRow; ++row) {
            for (int col = 0; col < m_desktopColumn; ++col) {
                if (itemGrid[row][col] > 0 && !pageData.contains(itemGrid[row][col])) {
                    pageData.push_back(itemGrid[row][col]);
                }
            }
        }
        setPageData(page, pageData);
        pageData.clear();
        page++;
    }
}
QList<quint32> TabletDesktopBackend::gridPageData(const int &page)
{
    QList<quint32> pageData;
    if (page >= m_itemGridStatus.count()) {
        qWarning() << "itemGridStatus page is incorrect" << __func__;
        return pageData;
    }
    QList<QList<int>> itemGrid = m_itemGridStatus.value(page);
    for (int row = 0; row < m_desktopRow; ++row) {
        for (int col = 0; col < m_desktopColumn; ++col) {
            if (itemGrid[row][col] > 0 && !pageData.contains(itemGrid[row][col])) {
                pageData.push_back(itemGrid[row][col]);
            }
        }
    }
    return pageData;
}

void TabletDesktopBackend::createDefaultGroup()
{
    m_widgetSettings->beginGroup("DefaultGroup");
    QStringList groupNameList = m_widgetSettings->allKeys();
    for (int i = 0; i < groupNameList.count(); ++i) {
        QStringList groupList = m_widgetSettings->value(groupNameList[i]).toStringList();
        QList<quint32> groupItemId;
        int itemId1 = m_database->queryIdFromDesktopName(findDesktopPathFromList(groupList[0]));
        groupItemId.push_back(itemId1);

        int itemId2 = m_database->queryIdFromDesktopName(findDesktopPathFromList(groupList[1]));
        groupItemId.push_back(itemId2);
        if (groupList.count() < 2 || itemId1 <= 0 || itemId2 <= 0) {
            qWarning() << __func__ << groupList[i] << "创建分组的应用数量或应用id不正确";
            continue;
        }

        removeGroupItemFromPage(itemId1);
        removeGroupItemFromPage(itemId2);
        int groupId = getIdleItemID();
        createGroup(groupId, groupItemId, groupNameList[i]);

        for (int itemIndex = 2; itemIndex < groupList.count(); ++itemIndex) {
            int itemId = m_database->queryIdFromDesktopName(findDesktopPathFromList(groupList[itemIndex]));
            if (itemId <= 0) {
                qWarning() << __func__ << "应用id不正确";
                continue;
            }
            groupItemId.push_back(itemId);
            removeGroupItemFromPage(itemId);
            QList<QList<quint32>> groupItemIds = allFlipSets[groupId];
            groupItemIds[0].push_back(itemId);
            setFlipSetData(groupId, groupItemIds);
        }

        updateExistIdlePage();
        fillUpIdlePosition();
        updateExistIdlePage();
        QList<quint32> itemList = allPage[m_idlePosPage];
        itemList.append(groupId);
        m_database->setPageData(m_idlePosPage, itemList);
        allPage[m_idlePosPage] = itemList;
    }
}

void TabletDesktopBackend::removeGroupItemFromPage(int itemId)
{
    QList<quint32> taskbarData = allScrollSets[0];
    if (taskbarData.contains(itemId)) {
        taskbarData.removeOne(itemId);
        setScrollSetData(0, taskbarData);
        allScrollSets[0] = taskbarData;
        return;
    }
    for (int pageId = 0; pageId < allPage.size(); pageId++) {
        QList<quint32> &itemlist = allPage[pageId];
        int itemIndex = itemlist.indexOf(itemId);
        if (itemIndex >= 0) {
            itemlist.removeAt(itemIndex);
            if (itemlist.size() == 0) {
                deleteLauncherPage(pageId);
            } else {
                setPageData(pageId, itemlist);
            }
            return;
        }
    }   
}

void TabletDesktopBackend::updatePageData()
{
    int pageCount = m_pageCount;
    m_itemGridStatus.clear();
    m_pageCount = 0;
    for (int pageIndex = 0; pageIndex <= pageCount; ++pageIndex) {
        m_pageCount = pageIndex;
        initItemGridStatus();
        QList<quint32> pageData = allPage[pageIndex];
        for (int itemIndex = 0; itemIndex < allPage[pageIndex].count(); ++itemIndex) {
            int itemId = allPage[pageIndex][itemIndex];
            if (m_baseItemList[itemId]->getType() == Type::Widget) {
                QList<int> placeholder = m_baseItemList[itemId]->getPlaceHolder();
                if (placeholder.count() != 2) {
                    qWarning() << __func__ << "获取小插件行列数失败";
                    return;
                }
                calculateWidgetPosition(QPoint(placeholder[0], placeholder[1]), itemId);
                pageData.removeOne(itemId);
            }
        }
        if (pageData.count() == 0) {
            continue;
        }
        for (int itemIndex = 0; itemIndex < pageData.count(); ++itemIndex) {
            int itemId = pageData[itemIndex];
            if (m_baseItemList[itemId]->getType() != Type::Icon && m_baseItemList[itemId]->getType() != Type::Group) {
                qWarning() << __func__ << "item的类型不正确";
            }
            calculateItemPosition(itemId, pageIndex);
        }
        qDebug() << "修改页数据之后 重新计算位置" << m_itemGridStatus;
        QList<quint32> desktopPageData = gridPageData(pageIndex);
        setPageData(pageIndex, desktopPageData);
        allPage[pageIndex] = desktopPageData;
    }
}

QString TabletDesktopBackend::findDesktopPathFromList(QString desktopName)
{
    QString desktopPath;
    for (int i = 0; i < m_baseItemList.size(); i++) {
        quint32 id = m_baseItemList.keys().at(i);
        if (m_baseItemList[id] && (m_baseItemList[id]->getType() == Type::Icon)) {
            IconItem *appItem = static_cast<IconItem *>(m_baseItemList[id]);
            desktopPath = appItem->getDesktopName();
            if (desktopPath.contains(desktopName)) {
                return desktopPath;
            }
        }
    }
    qWarning() << __func__ << "没有找到desktop的实际路径";
    return desktopPath;
}

}
