/*
 *
 *  * Copyright (C) 2023, 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 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, see <https://www.gnu.org/licenses/>.
 *  *
 *  * Authors: Nicole <buxiaoqing@kylinos.cn>
 *
 */

#include "ukuitaskbar.h"
#include "../panel/common/common.h"
#include <QPalette>
#include <QBrush>
#include <QDrag>
#include <QIcon>
#include <KWindowSystem>

UKUITaskBar::UKUITaskBar(IUKUIPanelPlugin *plugin, QWidget *parent) :
    QScrollArea(parent),
    m_plugin(plugin)
{
    setAcceptDrops(true);

    m_contextWidget.reset(new QWidget(this));

#ifdef QT_DEBUG
    m_contextWidget->setAutoFillBackground(true);
    m_contextWidget->setBackgroundRole(QPalette::Dark);
#else
    m_contextWidget->setAttribute(Qt::WA_TranslucentBackground);
#endif
    this->setWidget(m_contextWidget.get());
    this->horizontalScrollBar()->setVisible(false);
    this->verticalScrollBar()->setVisible(false);
    this->setFrameShape(QFrame::NoFrame);
    this->setWidgetResizable(true);
    this->setAcceptDrops(true);
    //设置背景透明
    QPalette pal = this->palette();
    pal.setBrush(QPalette::Window, QColor(Qt::transparent));
    this->setPalette(pal);

    m_layout.reset(new UKUi::GridLayout());
    m_layout->setMargin(0);
    m_layout->setStretch(UKUi::GridLayout::StretchHorizontal | UKUi::GridLayout::StretchVertical);
    m_layout->setEnabled(true);
    m_contextWidget->setLayout(m_layout.get());

    const QByteArray id(PANEL_SETTINGS);
    if (QGSettings::isSchemaInstalled(id)) {
        m_gsettings.reset(new QGSettings(id));
        m_gsettingKeys = m_gsettings->keys();
        if (m_gsettingKeys.contains(GROUPING_ENABLE))
            m_isGrouping = m_gsettings->get(GROUPING_ENABLE).toBool();
        if (m_gsettingKeys.contains(TASKBAR_BTN_SPAN))
            m_buttonSpan = m_gsettings->get((TASKBAR_BTN_SPAN)).toInt();
        connect(m_gsettings.get(), &QGSettings::changed, this, [&] (const QString &key) {
            if (key == TASKBAR_BTN_SPAN) {
                m_buttonSpan = m_gsettings->get((TASKBAR_BTN_SPAN)).toInt();
                this->realign();
            }
            if (key == GROUPING_ENABLE) {
                m_isGrouping = m_gsettings->get(GROUPING_ENABLE).toBool();
                this->realign();
            }
        });
    }

    initQuickLaunchApps();
    //应用黑白名单功能
    securityControlWatcher();
    initExistWindows();

    connect(kdk::WindowManager::self(), &WindowManager::windowAdded, this, &UKUITaskBar::onWindowAdded);
    connect(kdk::WindowManager::self(), &WindowManager::windowRemoved, this, &UKUITaskBar::onWindowRemove);
    connect(kdk::WindowManager::self(), &WindowManager::currentDesktopChanged, this, &UKUITaskBar::onCurrentDesktopChanged);

    QDBusConnection::sessionBus().connect(QString(), QString("/taskbar/quicklaunch"), "org.ukui.panel.taskbar", "AddToTaskbar", this, SLOT(pinToTaskbar(QString)));
    QDBusConnection::sessionBus().connect(QString(), QString("/taskbar/quicklaunch"), "org.ukui.panel.taskbar", "RemoveFromTaskbar", this, SLOT(unpinFromTaskbar(QString)));

    m_windowThumbnailManager = new WindowThumbnailManager();
    horizontalScrollBar()->setStyleSheet("QScrollBar {height:0px;}");
    verticalScrollBar()->setStyleSheet("QScrollBar {width:0px;}");

    //监听应用卸载
    appsUnistallWatcher();
}

UKUITaskBar::~UKUITaskBar()
{
    if (m_gsettings) {
        m_gsettings.reset(nullptr);
    }
    if (m_windowThumbnailManager) {
        delete m_windowThumbnailManager;
        m_windowThumbnailManager = nullptr;
    }
}

void UKUITaskBar::securityControlWatcher()
{
    m_interface = new QDBusInterface("com.kylin.kydevmonit.hedronclient","/kydevmonit/hedronclient",
                                    "com.kylin.kydevmonit.hedronclient",
                                    QDBusConnection::systemBus(),this);
    if (m_interface->isValid()) {
        QDBusReply<QString> replay = m_interface->call("get_application_control_mode");
        m_mode = replay;
        QDBusReply<QStringList> list = m_interface->call("get_application_control_list");
        m_controlAppList = list;
        securityControlApps(m_mode);
    }
    QDBusConnection::systemBus().connect(QString("com.kylin.kydevmonit.hedronclient"),
                                          QString("/com/kylin/kydevmonit/hedron_single"),
                                          QString("com.kylin.kydevmonit.hedronsingle"),
                                          QString("application_control_mode_signal"),
                                          this,
                                          SLOT(securityControlApps(QString))
                                          );

}

void UKUITaskBar::initQuickLaunchApps()
{
    //gsetting的方式读取写入 apps
    QList<QMap<QString, QVariant> > apps = m_plugin->settings()->readArray("apps");
    QString filename = QDir::homePath() + "/.config/ukui/panel.conf";
    QSettings user_qsettings(filename, QSettings::IniFormat);
    QStringList groupname = user_qsettings.childGroups();
    //为了兼容3.0版本和3.1版本，3.0版本的固定应用信息在quicklaunch里，3.1版本在taskbar里
    //备份还原时需要quicklaunch字段，故不能删除
    if (apps.isEmpty() && groupname.contains("quicklaunch")) {
        apps = copyQuicklaunchConfig();
    }
    addButtonForQuicklanch(apps);
}

void UKUITaskBar::initExistWindows()
{
    QList<WindowId> existWindowsList = kdk::WindowManager::windows();
    for (WindowId window : qAsConst(existWindowsList)) {
        onWindowAdded(window);
    }
}

QList<QMap<QString, QVariant>> UKUITaskBar::copyQuicklaunchConfig()
{
    QString filename = QDir::homePath() + "/.config/ukui/panel.conf";
    //若taskbar中没有apps，则把quicklaunch中的内容复制到taskbar
    qDebug()<<"Taskbar is empty, read apps from quicklaunch";
    QSettings user_qsettings(filename,QSettings::IniFormat);
    user_qsettings.beginGroup("quicklaunch");
    QList<QMap<QString, QVariant> > array;
    int size = user_qsettings.beginReadArray("apps");
    for (int i = 0; i < size; ++i) {
        user_qsettings.setArrayIndex(i);
        QMap<QString, QVariant> map;
        map["desktop"] = user_qsettings.value("desktop");
        if (array.contains(map)) {
            continue;
        } else {
            array << map;
        }
    }
    user_qsettings.endArray();
    user_qsettings.endGroup();
    user_qsettings.sync();
    return array;
}

void UKUITaskBar::addButtonForQuicklanch(QList<QMap<QString, QVariant> > apps)
{
    for (const QMap<QString, QVariant> &app : apps) {
        QString desktop = app.value("desktop", "").toString();
        qDebug() << "Pin " << desktop << "to Taskbar";
        if (!desktop.isEmpty()) {
            XdgDesktopFile xdg;
            if (xdg.load(desktop)) {
                if (!hasPinnedToTaskbar(desktop)) {
                    pinToTaskbar(desktop);
                }
            }
        } else {
            qDebug()<<"Desktop file path is not valid";
        }
    }
}

bool UKUITaskBar::hasPinnedToTaskbar(QString desktopFileName)
{
    QString configDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
    QString panelConfPath = QDir(configDir).filePath("ukui/panel.conf");
    QSettings settings(panelConfPath, QSettings::IniFormat);

    for (int i = 0; i < settings.beginReadArray("/taskbar/apps"); ++i) {
        settings.setArrayIndex(i);
        qDebug() << "settings.childKeys()" << settings.childKeys();
        if (settings.childKeys().contains(desktopFileName)) {
            return true;
        }
    }
    return false;
}

void UKUITaskBar::pinToTaskbar(QString desktopFileName)
{
    if (hasPinnedToTaskbar(desktopFileName)) {
        return;
    }

    for (auto i : m_groupList) {
        if (i->getDesktopFileName() == desktopFileName) {
            i->pinToTaskbar(desktopFileName);
            saveSettings();
            return;
        }
    }
    std::shared_ptr<UKUITaskGroup> group(new UKUITaskGroup("", desktopFileName, this));
    connect(group.get(), &UKUITaskGroup::unpinFromTaskbarSignal, this, &UKUITaskBar::unpinFromTaskbar, Qt::QueuedConnection);
    connect(group.get(), &UKUITaskGroup::enterGroup, this, &UKUITaskBar::enterGroupSlot);
    connect(group.get(), &UKUITaskGroup::leaveGroup, this, &UKUITaskBar::leaveGroupSlot);
    group->pinToTaskbar(desktopFileName);
    group->realign();
    m_layout->addWidget(group.get());
    m_groupList.append(group);
    saveSettings();
    group->setVisible(true);
    this->realign();

    getInitCornerMarkValue(group, desktopFileName);
}

void UKUITaskBar::unpinFromTaskbar(QString desktopFileName)
{
    for (int i = 0; i < m_groupList.size(); i++) {
        if (m_groupList.at(i)->getDesktopFileName() == desktopFileName) {
            m_groupList.at(i)->unpinFromTaskbar(desktopFileName);
            if (m_groupList.at(i)->getButtonsInfo().size() == 0) {
                m_layout->removeWidget(m_groupList.at(i).get());
                m_groupList.removeAt(i);
            }
        }
    }
    saveSettings();
    this->realign();
}

void UKUITaskBar::enterGroupSlot(QList<WindowId> winIdList, QString groupName, int x, int y)
{
    m_windowThumbnailManager->show(winIdList, groupName, x, y);
}

void UKUITaskBar::leaveGroupSlot(QString groupName)
{
    m_windowThumbnailManager->hide(groupName);
}

void UKUITaskBar::getInitCornerMarkValue(std::shared_ptr<UKUITaskGroup> &group, const QString &desktopFileName)
{
    QString desktop;
    int value;
    QString panelconf = QDir::homePath() + "/.config/ukui/panel.conf";
    QSettings cornerSettings(panelconf, QSettings::IniFormat);

    cornerSettings.beginGroup("CornerMark");
    desktop = cornerSettings.value("desktop").toString();
    value = cornerSettings.value("value").toInt();
    cornerSettings.endGroup();

    if (desktopFileName.compare(desktop) != 0) {
        return;
    }

    qDebug() << "[Panel] init to add cornermark";
    if (desktopFileName.compare(desktop) == 0) {
        if(!group->isHaveCornerMark()) {
            group->newKbage();
        }
        group->getKbadge()->setColor(Qt::red);
        group->getKbadge()->setValue(value);
        group->getKbadge()->setVisible(true);
        group->setHaveCornerMark(true);
        group->setCornerMarkSize();
    }
}

void UKUITaskBar::securityControlApps(QString mode)
{
    qDebug() << "Control Mode Changed" << mode;
    m_mode = mode;
    if (m_mode == "blacklist") {
        QDBusReply<QStringList> list = m_interface->call("get_application_control_list");
        m_controlAppList = list;
        qDebug() << "Blacklist Control App list is :" << m_controlAppList;
        removeBlackListApp();
    } else if (m_mode == "whitelist") {
        QDBusReply<QStringList> list = m_interface->call("get_application_control_list");
        m_controlAppList = list;
        qDebug() << "Whitelist Control App list is :" << m_controlAppList;
        addWhiteListApp();
    } else {
        for (std::shared_ptr<UKUITaskGroup> group : qAsConst(m_groupList)) {
            qDebug() << "Normal mode needs show all btn" << group->getDesktopFileName();
            group->setVisible(true);
        }
    }

}

void UKUITaskBar::removeBlackListApp()
{
    for (std::shared_ptr<UKUITaskGroup> group : qAsConst(m_groupList)) {
        if (m_controlAppList.contains(group->getDesktopFileName())) {
            qDebug() << "Blacklist mode needs hide:" << group->getDesktopFileName();
            group->setVisible(false);
        } else {
            group->setVisible(true);
        }
    }
}

void UKUITaskBar::addWhiteListApp()
{
    for (std::shared_ptr<UKUITaskGroup> group : qAsConst(m_groupList)) {
        if (m_controlAppList.contains(group->getDesktopFileName())) {
            qDebug() << "Whitelist mode needs show:" << group->getDesktopFileName();
            group->setVisible(true);
        } else {
            group->setVisible(false);
        }
    }
}

void UKUITaskBar::onCurrentDesktopChanged()
{
    securityControlApps(m_mode);
    for (auto i : m_groupList) {
        i->onCurrentDesktopChanged();
    }
    this->realign();
}

QSize UKUITaskBar::calcContextWidgetSize() {
    IUKUIPanel *panel = m_plugin->panel();
    unsigned int inVisiblePinnedButtonCount = 0,
                 inVisibleOpenedButtonCount = 0,
                 inVisibleGroupCount = 0,
                 visiblePinnedButtonCount = 0,
                 visibleOpenedButtonCount = 0,
                 visibleGroupCount = 0,
                 allOpenedButtonCount = 0,
                 allPinnedButtonCount = 0,
                 allGroupCount = 0;
    for (auto i : m_groupList) {
        ++allGroupCount;
        if (i->isVisible()) {
            ++visibleGroupCount;
            for (auto j : i->getButtonsInfo()) {
                if (j->isVisible()) {
                    if (j->windowId().toUInt() == 0) {
                        ++visiblePinnedButtonCount;
                        ++allPinnedButtonCount;
                    } else {
                        ++visibleOpenedButtonCount;
                        ++allOpenedButtonCount;
                    }
                } else {
                    if (j->windowId().toUInt() == 0) {
                        ++inVisiblePinnedButtonCount;
                        ++allPinnedButtonCount;
                    } else {
                        ++inVisibleOpenedButtonCount;
                        ++allOpenedButtonCount;
                    }
                }
            }
        } else {
            ++inVisibleGroupCount;
            if (i->isPinned()) {
                ++inVisiblePinnedButtonCount;
                ++allPinnedButtonCount;
                inVisibleOpenedButtonCount += i->getButtonsInfo().size() - 1;
                allOpenedButtonCount += i->getButtonsInfo().size() - 1;
            } else {
                inVisibleOpenedButtonCount += i->getButtonsInfo().size();
                allOpenedButtonCount += i->getButtonsInfo().size();
            }
        }
    }

    if (panel->isHorizontal()) {
        if (m_isGrouping) {
            return QSize(visibleGroupCount * panel->panelSize(), panel->panelSize());
        } else {
            return QSize(visibleOpenedButtonCount * panel->panelSize() * m_buttonSpan
                       + visiblePinnedButtonCount * panel->panelSize(), panel->panelSize());
        }
    } else {
        if (m_isGrouping) {
            return QSize(panel->panelSize(), visibleGroupCount * panel->panelSize());
        } else {
            return QSize(panel->panelSize(), (visiblePinnedButtonCount + visibleOpenedButtonCount) * panel->panelSize());
        }
    }
}

void UKUITaskBar::realign()
{
    IUKUIPanel *panel = m_plugin->panel();
    QSize btnSize = QSize(m_plugin->panel()->panelSize(), m_plugin->panel()->panelSize());

    for (std::shared_ptr<UKUITaskGroup> group : qAsConst(m_groupList)) {
        group->realign();
    }

    if (panel->isHorizontal()) {
        this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        this->setMinimumHeight(panel->panelSize());

        m_contextWidget->setFixedSize(calcContextWidgetSize());

        m_layout->setRowCount(panel->lineCount());
        m_layout->setColumnCount(0);

    } else {
        this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        this->setMinimumWidth(panel->panelSize());

        m_contextWidget->setFixedSize(calcContextWidgetSize());

        m_layout->setRowCount(0);
        m_layout->setColumnCount(panel->lineCount());
        qWarning() << "panel->lineCount()" << panel->lineCount();
    }
    m_layout->setCellMinimumSize(btnSize);
    if (m_isGrouping || !m_plugin->panel()->isHorizontal()) {
        m_layout->setCellMaximumSize(btnSize * m_buttonSpan);
    } else {
        m_layout->setCellMaximumSize(btnSize * m_buttonSpan);
    }
}

QString UKUITaskBar::tranWinIdToDesktop(WindowId window)
{
    QString desktopName;
    QDBusInterface *ukuiSearchInterface = new QDBusInterface("com.ukui.search.appdb.service",
                                          "/org/ukui/search/appDataBase/dbManager",
                                          "org.ukui.search.appDBManager");
    if (ukuiSearchInterface->isValid()) {
        QDBusReply<QString> reply = ukuiSearchInterface->call("tranWinIdToDesktopFilePath", QVariant::fromValue(QDBusVariant(window)));
            if (reply.isValid()) {
                desktopName = reply.value();
            } else {
                qDebug() << ukuiSearchInterface->lastError();
            }
    }
    if (desktopName.isEmpty()) {
        desktopName = tranClassNameToDesktop(window);
    }
    return desktopName;
}

QString UKUITaskBar::tranClassNameToDesktop(WindowId window)
{
    QDBusInterface iface(UKUI_PANEL_DAEMON,
                         UKUI_PANEL_DAEMON_PATH,
                         UKUI_PANEL_DAEMON_INTERFACE,
                         QDBusConnection::sessionBus());
    if (!iface.isValid()) {
        qDebug() << "Invalid Interface:" << iface.lastError();
        return "";
    }
    QDBusReply<QString> reply = iface.call(UKUI_PANEL_DAEMON_METHOD, window.toInt());
    if (!reply.isValid()) {
        qDebug() << "Invalid QDBusReply:" << reply.error();
        return "";
    }
    QString processExeName = reply.value();
    qDebug() << __func__ << processExeName;
    return processExeName;
}

void UKUITaskBar::wheelEvent(QWheelEvent *event)
{
    IUKUIPanel *panel = m_plugin->panel();
    if (panel->isHorizontal()) {
        if (event->delta() >= 0) {
            horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 40);
        } else {
            horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 40);
            if (horizontalScrollBar()->value() > m_contextWidget->width()) {
                horizontalScrollBar()->setValue(m_contextWidget->width());
            }
        }
    } else {
        if (event->delta() >= 0) {
            verticalScrollBar()->setValue(verticalScrollBar()->value() - 40);
        } else {
            verticalScrollBar()->setValue(verticalScrollBar()->value() + 40);
        }
    }
}

void UKUITaskBar::mousePressEvent(QMouseEvent *event)
{
    if (!(event->buttons() & Qt::LeftButton)) {
        return;
    }
    m_canDragging = m_contextWidget->geometry().contains(mapToParent(event->pos()));
    event->setAccepted(true);
}

void UKUITaskBar::mouseMoveEvent(QMouseEvent *event)
{
    if (!(event->buttons() & Qt::LeftButton)) {
        return;
    }

    if (m_contextWidget->geometry().contains(mapToParent(event->pos())) && m_canDragging) {

        UKUITaskButton *taskbutton = static_cast<UKUITaskButton*>(childAt(event->pos()));
        if (!taskbutton || !taskbutton->objectName().contains("UKUITaskButton"))
            return;
        UKUITaskGroup* taskgroup = static_cast<UKUITaskGroup*>(taskbutton->parentWidget());

        QByteArray itemData;
        QDataStream dataStream(&itemData, QIODevice::WriteOnly);
        dataStream << m_layout->indexOf(taskgroup);

        QDrag *drag = new QDrag(taskgroup);

        drag->setMimeData(new QMimeData());
        drag->setPixmap(taskbutton->icon().pixmap(m_plugin->panel()->iconSize()));
        drag->setHotSpot({0, 0});
        drag->exec();

        event->setAccepted(true);
    } else {
        event->setAccepted(false);
    }
}

void UKUITaskBar::dragEnterEvent(QDragEnterEvent *event)
{
    if (m_canDragging) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}

void UKUITaskBar::dragMoveEvent(QDragMoveEvent *event)
{
    if (m_contextWidget->geometry().contains(mapToParent(event->pos()))) {
        UKUITaskButton *taskbuttonDestination = static_cast<UKUITaskButton*>(childAt(event->pos()));
        if (!taskbuttonDestination)
            return;

        UKUITaskGroup* taskgroupDestination = static_cast<UKUITaskGroup*>(taskbuttonDestination->parentWidget());
        if (!taskgroupDestination)
            return;

        UKUITaskGroup* taskgroupSource = static_cast<UKUITaskGroup*>(event->source());
        if (!taskgroupSource)
            return;

        int targetSource = m_layout->indexOf(taskgroupSource);

        int targetDestination = m_layout->indexOf(taskgroupDestination);

        qDebug() << "move from: " << targetSource << "to: " << targetDestination;
        if (targetSource < 0 || targetDestination < 0 || targetSource == targetDestination)
            return;

        m_layout->moveItem(targetSource, targetDestination, true);

        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }

        event->setAccepted(true);
    } else {
        event->setAccepted(false);
    }
}

void UKUITaskBar::dropEvent(QDropEvent *event)
{
    //拖拽放下时更新button的iconGeometry
    for (std::shared_ptr<UKUITaskGroup> group : qAsConst(m_groupList)) {
        group->realign();
    }
    event->setAccepted(false);
}

bool UKUITaskBar::acceptWindow(const WindowId& window)
{
    QString platform = QGuiApplication::platformName();
    if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) {
        QString windowTitle = WindowManager::getWindowTitle(window);
        if (windowTitle == "UKUI Panel") {
            return false;
        }
        bool isSkipTaskbar = kdk::WindowManager::skipTaskBar(window);
        if (isSkipTaskbar) {
            return false;
        }
        return true;
    } else {
        int wid = window.toInt();
        QFlags<NET::WindowTypeMask> ignoreList;
        ignoreList |= NET::DesktopMask;
        ignoreList |= NET::DockMask;
        ignoreList |= NET::SplashMask;
        ignoreList |= NET::ToolbarMask;
        ignoreList |= NET::MenuMask;
        ignoreList |= NET::PopupMenuMask;
        ignoreList |= NET::NotificationMask;
        ignoreList |= NET::UtilityMask;

        KWindowInfo info(wid, NET::WMWindowType | NET::WMState, NET::WM2TransientFor);
        if (!info.valid()) {
            return false;
        }
        if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) {
            return false;
        }
        if (info.state() & NET::SkipTaskbar) {
            return false;
        }
        // WM_TRANSIENT_FOR hint not set - normal window
        WId transFor = info.transientFor();
        if (transFor == 0 || transFor == wid || transFor == (WId) QX11Info::appRootWindow()) {
            return true;
        }

        info = KWindowInfo(transFor, NET::WMWindowType);
        QFlags<NET::WindowTypeMask> normalFlag;
        normalFlag |= NET::NormalMask;
        normalFlag |= NET::DialogMask;
        normalFlag |= NET::UtilityMask;
        return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
    }

}

void UKUITaskBar::onWindowAdded(const WindowId& window)
{
    if (acceptWindow(window)) {
        const QString groupName = kdk::WindowManager::getWindowGroup(window);
        const QString desktopFileName = tranWinIdToDesktop(window);
        qDebug() << "Add window id is :" << window << groupName;
        m_windowId2GroupName.insert(window, groupName);

        if (groupName == "") {
            qWarning() << "Can't get this APP's group name";
            return;
        }
        for (int i = 0; i < m_groupList.size(); i++) {
            if (!m_groupList.at(i)->getGroupName().isEmpty() && m_groupList.at(i)->getGroupName() != groupName) {
                continue;
            }
            if (m_groupList.at(i)->getGroupName() == groupName && groupName != "kylin-kmre-window") {
                qDebug() << "this app has been opened";
                m_groupList.at(i)->addWindow(window);
                if(m_groupList.at(i)->isHaveCornerMark()) {
                    m_groupList.at(i)->appsCornerMarkChangedSlot(m_groupList.at(i)->getDesktopFileName(), m_groupList.at(i)->getKbadge()->value());
                }
                this->realign();
                return;
            } else if (m_groupList.at(i)->getDesktopFileName() == desktopFileName
                       && desktopFileName != "" && m_groupList.at(i)->isPinned()) {
                m_groupList.at(i)->addWindow(window);
                if(m_groupList.at(i)->isHaveCornerMark()) {
                    m_groupList.at(i)->appsCornerMarkChangedSlot(m_groupList.at(i)->getDesktopFileName(), m_groupList.at(i)->getKbadge()->value());
                }
                qDebug() << "this app has been pinned";
                this->realign();
                return;
            }
        }
        std::shared_ptr<UKUITaskGroup> group(new UKUITaskGroup(groupName, "", this));
        group->setDesktopFileName(desktopFileName);
        connect(group.get(), &UKUITaskGroup::pinToTaskbarSignal, this, &UKUITaskBar::pinToTaskbar);
        connect(group.get(), &UKUITaskGroup::unpinFromTaskbarSignal, this, &UKUITaskBar::unpinFromTaskbar, Qt::QueuedConnection);
        connect(group.get(), &UKUITaskGroup::enterGroup, this, &UKUITaskBar::enterGroupSlot);
        connect(group.get(), &UKUITaskGroup::leaveGroup, this, &UKUITaskBar::leaveGroupSlot);

        group->realign();
        group->addWindow(window);
        m_layout->addWidget(group.get());
        m_groupList.append(group);
        group->setVisible(true);
        this->realign();
    }
}

void UKUITaskBar::onWindowRemove(const WindowId& window)
{
    qDebug() << "Remove window id is :" << window << m_windowId2GroupName.value(window);
    const QString groupName = m_windowId2GroupName.value(window);

    for (int i = 0; i < m_groupList.size(); i++) {
        if (m_groupList.at(i)->getGroupName() == "kylin-kmre-window"
                && m_groupList.at(i)->getButtonsInfo().keys().contains(window)) {
            m_groupList.at(i)->removeWindow(window);
        }
        if (m_groupList.at(i)->getGroupName() == groupName && groupName != "kylin-kmre-window") {
            m_groupList.at(i)->removeWindow(window);

            if(m_groupList.at(i)->isPinned() && m_groupList.at(i)->isHaveCornerMark()) {
                m_groupList.at(i)->appsCornerMarkChangedSlot(m_groupList.at(i)->getDesktopFileName(), m_groupList.at(i)->getKbadge()->value());
            }
        }

        if (m_groupList.at(i)->getButtonsInfo().size() == 0) {
            m_layout->removeWidget(m_groupList.at(i).get());
            m_groupList.removeAt(i);
        }
    }
    m_windowId2GroupName.remove(window);
    this->realign();
    return;
}

void UKUITaskBar::saveSettings()
{
    PluginSettings *settings = m_plugin->settings();
    settings->remove("apps");
    QList<QMap<QString, QVariant>> hashList;
    int size = m_layout->count();
    for (int j = 0; j < size; ++j) {
        UKUITaskGroup *pinBtn = qobject_cast<UKUITaskGroup*>(m_layout->itemAt(j)->widget());
        if (!pinBtn || !pinBtn->isPinned()) {
            continue;
        }
        QMap<QString, QVariant> map;
        map["desktop"] = pinBtn->getDesktopFileName();
        hashList << map;
    }
    settings->setArray("apps", hashList);
}

void UKUITaskBar::appsUnistallWatcher()
{
    m_fsWatcher.reset(new QFileSystemWatcher());
    m_fsWatcher->addPath(DESKTOP_FILE_PATH);
    m_fsWatcher->addPath(ANDROID_DESKTOP_FILE_PATH);
    directoryUpdated(DESKTOP_FILE_PATH);
    directoryUpdated(ANDROID_DESKTOP_FILE_PATH);
    connect(m_fsWatcher.get(), &QFileSystemWatcher::directoryChanged, [this](){
        directoryUpdated(DESKTOP_FILE_PATH);
        directoryUpdated(ANDROID_DESKTOP_FILE_PATH);
    });
}

void UKUITaskBar::directoryUpdated(const QString &path)
{
    // 比较最新的内容和保存的内容找出区别(变化)
    QStringList currentrylist = m_currentContentsMap[path];
    const QDir dir(path);
    QStringList newentrylist = dir.entryList(QDir::NoDotAndDotDot  | QDir::AllDirs | QDir::Files, QDir::DirsFirst);
    QSet<QString> newdirset = QSet<QString>::fromList(newentrylist);
    QSet<QString> currentdirset = QSet<QString>::fromList(currentrylist);

    // 文件已被移除
    QSet<QString> deletedfiles = currentdirset - newdirset;
    QStringList deletefile = deletedfiles.toList();

    // 更新当前设置
    m_currentContentsMap[path] = newentrylist;

    if (deletefile.isEmpty()) {
        return;
    }
    foreach (QString file, deletefile) {
        qDebug() << "Uninstall App is:" << path + file;
        unpinFromTaskbar(path + file);
    }
}

