//
// Created by uos on 2022/3/14.
//

#include "MainWindow.h"
#include "utils/Utils.h"
#include "utils/errorCodes.h"
#include "utils/FsTab.h"
#include "utils/Device.h"
#include <DTitlebar>
#include <QHBoxLayout>
#include <DBackgroundGroup>
#include <QStandardItemModel>
#include <QTimer>
#include <QVariant>
#include <DStyleOption>
#include <DStandardItem>
#include <QMargins>
#include <QModelIndex>
#include <DPalette>
#include <DWindowManagerHelper>
#include <selinux/selinux.h>
#include "common/CommonFunc.h"

Q_DECLARE_METATYPE(QMargins)

const int BACKUP_BUTTON_ID = 0;
const int RESTORE_BUTTON_ID = 1;
const int ADVANCED_BUTTON_ID = 2;

const QString RecoveryServiceName = "com.deepin.uosrecovery";
const QString RecoveryServicePath = "/com/deepin/uosrecovery";
const QString MainWindowObjName = "uos-recovery-gui-MainWindow-obj-name";
const QString MainWindowTitleBar = "uos-recovery-gui-MainWindow-TitleBar";

QString MainWindow::getErrorMsgByErrorCode(int errCode)
{
    QMap<int, QString> allErrInfo = {
        {OStree::OSTREE_ERR_STORAGE_PATH_NOT_EXIST,
         tr("System backup error: the storage path does not exist.")},

         {OStree::OSTREE_ERR_INSUFFICIENT_DISK_SPACE,
         tr("System backup error: the storage path does not exist.")},

         {OStree::OSTREE_ERR_UPDATE_GRUB_FAILED,
         tr("System backup error: failed to update the grub.")},

         {OStree::OSTREE_ERR_MOUNT_OR_UMOUNT_FAILED,
         tr("System backup error: failed to mount and unmount the disk.")},

         {OStree::OSTREE_ERR_INIT_REPO_FAILED,
         tr("System backup error: initialization failed.")},

         {OStree::OSTREE_ERR_SUBMIT_FAILED,
         tr("System backup error: failed to submit the backup.")},

         {OStree::OSTREE_ERR_CHECKOUT_FAILED,
         tr("System backup error: failed to check out the version.")},

         {OStree::OSTREE_ERR_CANNOT_DELETE,
         tr("File deletion error: the backup file cannot be deleted.")}
    };

    if (allErrInfo.contains(errCode)) {
        return allErrInfo.value(errCode);
    }

    return "";
}

// DTK默认实现不满足多个DMainWindow的场景，需要自己实现
void MainWindow::onNewProcessInstance()
{
    for (QWidget *window : qApp->topLevelWidgets()) {
        DMainWindow *pDMainWindow = qobject_cast<DMainWindow*>(window);
        if (nullptr != pDMainWindow) {
            QString objName = pDMainWindow->objectName();
            QString mainTitleBarAccessibleName;
            DTitlebar * titleBar = pDMainWindow->titlebar();
            if (nullptr != titleBar) {
                mainTitleBarAccessibleName = titleBar->accessibleName();
            }
        //    qInfo()<<"objName = "<<objName<<", mainTitleBarAccessibleName = "<<mainTitleBarAccessibleName;
            // 避免其他DMainWindow类设置同名，加上titleBar的AccessibleName加强校验
            if (MainWindowObjName != objName && MainWindowTitleBar != mainTitleBarAccessibleName) {
                continue;
            }

            // 如果窗口最小化或者隐藏了，应当先将其show出來
            if (pDMainWindow->isMinimized() || pDMainWindow->isHidden()) {
                pDMainWindow->showNormal();
            }

            pDMainWindow->activateWindow();
            pDMainWindow->raise();
            break;
        }
    }
}

MainWindow::MainWindow(QWidget *parent) : DMainWindow(parent)
{
    registerALLMetaType();
    connect(DGuiApplicationHelper::instance(), SIGNAL(newProcessInstance(qint64, const QStringList &)),
            this, SLOT(onNewProcessInstance()));
    this->setObjectName(MainWindowObjName);

    QSettings versionFile("/etc/os-version", QSettings::IniFormat);
    versionFile.beginGroup("Version");
    m_osMajorVer = versionFile.value("MajorVersion").toInt();
    m_osMinorVer = versionFile.value("MinorVersion").toInt();
    versionFile.endGroup();

    m_isImmutable = Utils::isImmutableSystem();
    m_isCommunity = Utils::isCommunity();
    m_isDeepinBootKitExist = Utils::isDeepinBootKitExist();
    if (Utils::isGhostOnly()) {
        m_isGhostOnly = true;
    }

    this->setAccessibleName("uos-recovery-gui-MainWindow");
    m_centralLayout = new QHBoxLayout;
    auto centerWidget = new DFrame;
    centerWidget->setObjectName("centerWidget");
    centerWidget->setAccessibleName("uos-recovery-gui-CenterWidget");
    centerWidget->setLineWidth(0);
    centerWidget->setLayout(m_centralLayout);

    auto mainLayout = new QHBoxLayout;
    auto mainWidget = new DWidget;
    mainWidget->setObjectName("mainWidget");
    mainWidget->setAccessibleName("uos-recovery-gui-MainWidget");
    mainLayout->addWidget(centerWidget);
    mainLayout->setContentsMargins(10, 10, 10, 10);
    setCentralWidget(mainWidget);
    centralWidget()->setLayout(mainLayout);

    //标题栏
    DTitlebar *titleBar = this->titlebar();
    titleBar->setIcon(QIcon::fromTheme("uos-recovery"));
    titleBar->setAccessibleName(MainWindowTitleBar);

    auto menu = titleBar->menu();
    if (!menu) {
        menu = new QMenu(this);
    }
    titleBar->setMenu(menu);

    m_buttonBox = new DButtonBox(this);
    m_backupBtn = new DButtonBoxButton(tr("Backup"));
    m_restoreBtn = new DButtonBoxButton(tr("Restore"));
    m_advancedBtn = new DButtonBoxButton(tr("Advanced"));
    m_backupBtn->setAccessibleName("uos-recovery-gui-Backup");
    m_restoreBtn->setAccessibleName("uos-recovery-gui-Restore");
    m_advancedBtn->setAccessibleName("uos-recovery-gui-Advanced");
    m_buttonBox->setAccessibleName("uos-recovery-gui-BRA-Box");
    if (m_isCommunity) {
        m_buttonBox->setButtonList({m_backupBtn, m_restoreBtn}, true);
    } else {
        if (m_isGhostOnly) {
            m_buttonBox->setButtonList({m_advancedBtn}, true);
        } else {
            m_buttonBox->setButtonList({m_backupBtn, m_restoreBtn, m_advancedBtn}, true);
        }
    }

    if (!m_isGhostOnly) {
        m_buttonBox->setId(m_backupBtn, BACKUP_BUTTON_ID);
        m_buttonBox->setId(m_restoreBtn, RESTORE_BUTTON_ID);
    }

    if (!m_isCommunity) {
        m_buttonBox->setId(m_advancedBtn, ADVANCED_BUTTON_ID);
    }

    // m_buttonBox->setContentsMargins(3, 3, 3, 3); // 跟UI对齐后，DTK目前还没实现新的效果，采用原来的不加边距
    titleBar->addWidget(m_buttonBox, Qt::AlignCenter);
    connect(m_buttonBox, &DButtonBox::buttonPressed, this, &MainWindow::onModuleChange);

    //设置
    if (m_isSupportSettings && (m_isDeepinBootKitExist || !m_isGhostOnly)) {
        auto settingAction = new QAction(tr("Settings"), this);
        menu->addAction(settingAction);
        connect(settingAction, &QAction::triggered, this, &MainWindow::showSettingDialog);
        if (Utils::isOStree() || m_isImmutable) {
            this->setMenuActionEnabled(tr("Settings"), false); // OStree 环境不支持修改
        }
    }

    //操作日志
    auto logAction = new QAction(tr("Logs"), this);
    menu->addAction(logAction);
    connect(logAction, &QAction::triggered, this, &MainWindow::showLogDialog);

    //备份文件管理
    auto backFileManagerAction = new QAction(tr("Backup files"), this);
    menu->addAction(backFileManagerAction);
    connect(backFileManagerAction, &QAction::triggered, this, &MainWindow::showBackupFileManagerDialog);


    //上一步按钮
    m_backwardBtn = new DIconButton(this); //上一步按钮
    m_backwardBtn->setAccessibleName("backwardButton");
    m_backwardBtn->setIcon(QStyle::SP_ArrowBack);
    m_backwardBtn->hide();
    titleBar->addWidget(m_backwardBtn, Qt::AlignLeft | Qt::AlignVCenter);
    connect(m_backwardBtn, &DIconButton::clicked, this, &MainWindow::onBackWardClick);

    QTimer::singleShot(0, this, &MainWindow::initAllModule); //初始化所有模块
}

MainWindow::~MainWindow()
{

}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (nullptr != m_logDialog) {
        m_logDialog->close();
        m_logDialog->deleteLater();
        m_logDialog = nullptr;
    }

    if (nullptr != m_backupFileManagerDialog) {
        m_backupFileManagerDialog->close();
        m_backupFileManagerDialog->deleteLater();
        m_backupFileManagerDialog = nullptr;
    }

    QMainWindow::closeEvent(event);
}

void MainWindow::pushWidget(ModuleInterface *const inter, QWidget *const w)
{
    m_contentStack.push({inter, w});
    if (m_contentStack.size() >= 2) {
        m_backwardBtn->show();
    } else {
        m_backwardBtn->hide();
    }
}

void MainWindow::popAllWidget()
{
    while (!m_contentStack.isEmpty()) {
        auto content = m_contentStack.pop();
        m_centralLayout->removeWidget(content.second);
        content.second->hide();
    }
}

void MainWindow::popWidget()
{
    if (!m_contentStack.isEmpty()) {
        auto content = m_contentStack.pop();
        m_centralLayout->removeWidget(content.second);
        content.second->hide();
    }

    if (m_contentStack.size() < 2) {
        m_backwardBtn->hide();
    }
}

void MainWindow::popWidgetAndDelete()
{
    if (!m_contentStack.isEmpty()) {
        auto content = m_contentStack.pop();
        m_centralLayout->removeWidget(content.second);
        content.second->hide();
        content.second->deleteLater();
    }
}

void MainWindow::back()
{
    onBackWardClick();
}

void MainWindow::backHome()
{
    while (!m_contentStack.isEmpty()) {
        auto content = m_contentStack.pop();
        if (m_contentStack.isEmpty()) {
            m_contentStack.push(content);
            content.second->show();
            content.second->setFocus();
            m_backwardBtn->hide();
            break;
        } else {
            m_centralLayout->removeWidget(content.second);
            content.second->hide();
        }
    }
}

void MainWindow::enableBackWard(bool enable)
{
    m_backwardBtn->setEnabled(enable);
    m_backwardBtn->setVisible(enable);
}

void MainWindow::enableModule(bool enable)
{
    m_buttonBox->setEnabled(enable);
}

void MainWindow::setModuleVisible(ModuleInterface *const inter, const bool visible)
{

}

void MainWindow::setCurrentWidget(ModuleInterface *const inter, QWidget *const w)
{
    if (!m_contentStack.isEmpty()) {
        m_centralLayout->removeWidget(m_contentStack.top().second);
        m_contentStack.top().second->hide();
    }
    pushWidget(inter, w);
    m_centralLayout->addWidget(w);
    w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    w->show();
    w->setFocus();
}


ModuleInterface *MainWindow::getCurrentModule()
{
    return nullptr;
}

void MainWindow::showSettingDialog()
{
    if (!Utils::authorization()) {
        return;
    }

    auto currDestReply = m_interface->GetBackupDeviceUUID(m_rootUUID);
    currDestReply.waitForFinished();
    if (!currDestReply.isValid()) {
        qCritical() << Q_FUNC_INFO << currDestReply.error();
        return;
    }
    m_currDestUUID = currDestReply.value();

    if (m_selectPartitionDialog == nullptr) {
        m_selectPartitionDialog = new SelectPartitionDialog(this);
        m_selectPartitionDialog->setWindowIcon(QIcon::fromTheme("uos-recovery"));
        connect(m_selectPartitionDialog, &SelectPartitionDialog::destDeviceChange, this,
                &MainWindow::onDestPartitionChange, Qt::QueuedConnection);
    } else {
        m_selectPartitionDialog->setErrorText("");
        m_selectPartitionDialog->activateWindow();
        m_selectPartitionDialog->raise();
    }

    auto reply = m_interface->ListPartition();
    reply.waitForFinished();
    if (!reply.isValid()) {
        qCritical() << Q_FUNC_INFO << reply.error();
        return;
    }
    QString partition = reply.value();

    m_selectPartitionDialog->setData(partition, m_currDestUUID);
    m_selectPartitionDialog->setDestUUID(m_currDestUUID);
    m_selectPartitionDialog->showToCenter();
}

void MainWindow::onDestPartitionChange(const QJsonObject &jsonObject)
{
    bool fsTypeSupported = false;
    if (jsonObject.contains("fsTypeSupported")) {
        fsTypeSupported = jsonObject.value("fsTypeSupported").toBool();
    }

    if (!fsTypeSupported) {
        m_selectPartitionDialog->onShowResult(static_cast<int> (ErrorCode::PartitionNotSupportRecovery));
        return;
    }

    m_backupModule->setSystemBackupSpaceTips("");
    auto uuid = jsonObject.value("uuid").toString();
    if (uuid != m_destUUID) {
        auto reply = m_interface->CheckFullSystemBackupDiskSpace(m_rootUUID, uuid);
        reply.waitForFinished();
        if (!reply.isValid()) {
            qCritical() << reply.error();
            return;
        }
    } else {
        auto checkSpaceReply = m_interface->CheckIncSystemBackupSpace(uuid);
        checkSpaceReply.waitForFinished();
        if (!checkSpaceReply.isValid()) {
            qCritical() << checkSpaceReply.error();
            return;
        }
    }

    m_destPartitionJson = jsonObject;
    m_currDestUUID = uuid;
}

void MainWindow::showLogDialog()
{
    if (m_logDialog == nullptr) {
        m_logDialog = new LogDialog();
    } else {
        m_logDialog->activateWindow();
        m_logDialog->raise();
    }

    QString curUserName = Utils::getUserName();
    bool isAdmin = Utils::isAdminUser(curUserName);
    QJsonObject request;
    OperateLogQuery query;
    if (isAdmin) {
        query.mask = 0;
    } else {
        query.mask = 0x08;
    }
    query.username = curUserName;
    query.orderByTimeDesc = true; // 日志默认按照时间排序显示
    //request = query.marshal();
    auto logReply = m_interface->ListOperateLogs(query);
    logReply.waitForFinished();
    if (!logReply.isValid()) {
        qCritical() << logReply.error();
        return;
    }

    OperateLogList operateLogList;
    QJsonObject jsonRoot = Utils::QStringToJson(logReply.value());
    QJsonArray logsObject = jsonRoot.value("logs").toArray();
    for (auto jsonObject : logsObject) {
        OperateLog operateLog;
        operateLog.unmarshal(jsonObject.toObject());
        operateLogList.append(operateLog);
    }
    m_logDialog->setData(operateLogList);
    m_logDialog->showToCenter();
}

void MainWindow::showBackupFileManagerDialog()
{
    if (m_backupFileManagerDialog == nullptr) {
        m_backupFileManagerDialog = new BackupFileManagerDialog();
        connect(m_interface, &ComDeepinDaemonUosrecoveryInterface::Success, [this] (const QString &msg) {
            QJsonObject jsonObject = Utils::QStringToJson(msg);
            if (!jsonObject.isEmpty() && jsonObject.value("operateType").toInt() == static_cast<int>(OperateType::removeBackup)) {
                auto operateId = jsonObject.value("operateId").toString();
                m_backupFileManagerDialog->removeBackupInfo(operateId);
            }
        });

        connect(m_interface, &ComDeepinDaemonUosrecoveryInterface::Error, this, &MainWindow::onError);

        connect(m_backupFileManagerDialog, &BackupFileManagerDialog::notifyDeleteBackupInfo, [=](const BackupInfo &backupInfo){
            if (m_interface->IsRunning()) {
                QString operateID;
                QString userName;
                int opType;
                int progress;
                m_interface->GetContext(operateID, userName, opType, progress);
                QString opTypeDes = Common::GetOperateTypeDes(opType);
                QString tips = tr("Task conflict, user %1's task %2 has not been completed").arg(userName).arg(opTypeDes);
                m_backupFileManagerDialog->setDeleteWidgetStatus(true, false, backupInfo.operateID);
                m_backupFileManagerDialog->showErrorDlg(tips);
                return;
            }
            RemoveUserDataBackupRequest removeUserDataBackupRequest;
            removeUserDataBackupRequest.username = Utils::getUserName();
            removeUserDataBackupRequest.backupInfo = backupInfo;
            removeUserDataBackupRequest.operateID = QUuid::createUuid().toString();

            //QJsonObject request = removeUserDataBackupRequest.marshal();
            auto removeReply = m_interface->RemoveBackupInfo(removeUserDataBackupRequest);
            removeReply.waitForFinished();
            if (!removeReply.isValid()) {
                qCritical() << "RemoveBackupInfo removeReply isInvalid, error: " << removeReply.error();
                m_backupFileManagerDialog->setDeleteWidgetStatus(true, false, backupInfo.operateID);
                return ;
            }

            int retCode = removeReply.value();
            if (retCode != ErrorCode::OK) {
                qCritical()<<"RemoveBackupInfo failed, retCode = "<<retCode;
                m_backupFileManagerDialog->setDeleteWidgetStatus(true, false, backupInfo.operateID);
                return;
            }
        });
    } else {
        m_backupFileManagerDialog->activateWindow();
        m_backupFileManagerDialog->raise();
    }

    QString curUserName = Utils::getUserName();
    bool isAdmin = Utils::isAdminUser(curUserName);
    auto userDataReply = m_interface->ListUserDataBackup(curUserName);
    userDataReply.waitForFinished();
    if (!userDataReply.isValid()) {
        qCritical() << userDataReply.error();
        return;
    }

    BackupInfoList backupInfoList;
    QJsonObject jsonRoot = Utils::QStringToJson(userDataReply.value());
    QJsonArray jsonBackupInfo = jsonRoot.value("backup").toArray();
    for (auto jsonObject : jsonBackupInfo) {
        BackupInfo info;
        info.unmarshal(jsonObject.toObject());
        backupInfoList.append(info);
    }
    m_backupFileManagerDialog->setDataBackupInfoData(backupInfoList);

    GhostLogQuery ghostQuery;
    ghostQuery.mask = 0;
    ghostQuery.userName = curUserName;
    ghostQuery.orderByTimeDesc = true; // 日志默认按照时间排序显示
    //QJsonObject request = ghostQuery.marshal();
    auto logReply = m_interface->QueryUImgBackup(ghostQuery);
    logReply.waitForFinished();
    if (!logReply.isValid()) {
        qCritical() << "QueryUImgBackup err: "<<logReply.error();
    }

    BackupInfoList ghostLogList;
    QJsonObject jsonGhostRoot = Utils::QStringToJson(logReply.value());
    QJsonArray logsObject = jsonGhostRoot.value("logs").toArray();
    for (auto jsonObject : logsObject) {
        GhostLog ghostLog;
        ghostLog.unmarshal(jsonObject.toObject());
        BackupInfo ghostInfo;
        ghostInfo.operateID = ghostLog.operateID;
        ghostInfo.username = ghostLog.userName;
        ghostInfo.operateType = static_cast<int> (ghostLog.operateType);
        ghostInfo.status = ghostLog.status;
        ghostInfo.backupDevUUID = ghostLog.deviceUUID;
        ghostInfo.backupDeviceRemovable = ghostLog.isRemoveable;
        ghostInfo.backupPath = ghostLog.path;
        ghostInfo.startTime = ghostLog.time;
        ghostInfo.systemVersion = ghostLog.path;
        ghostInfo.remark = ghostLog.deviceUUID;
        ghostLogList.append(ghostInfo);
    }
    m_backupFileManagerDialog->setGhostInfoData(ghostLogList);

    if (isAdmin) {
        auto systemBackupReply = m_interface->ListSystemBackup();
        systemBackupReply.waitForFinished();
        if (!systemBackupReply.isValid()) {
            qCritical() <<systemBackupReply.error();
            return;
        }

        BackupInfoList sysBackupList;
        jsonRoot = Utils::QStringToJson(systemBackupReply.value());
        jsonBackupInfo = jsonRoot.value("backup").toArray();
        for (auto jsonObject : jsonBackupInfo) {
            BackupInfo info;
            info.unmarshal(jsonObject.toObject());
            // 系统备份用户统一显示成 管理员， 原因是 ostree 场景下原子更新不提供用户
            info.username = tr("Administrator");
            if (info.recoveryType == static_cast<int>(RecoveryType::OSTree)) {
                if (info.submissionType == CommitType::SystemCommit) {
                    info.remark = tr("Automatical backup before system updates");
                } else if (info.submissionType == CommitType::InstallerCommit) {
                    info.remark = tr("Initial backup during system installation");
                    info.systemVersion = tr("Initial backup");
                }
            } else if (info.operateType == static_cast<int> (OperateType::ImmutableSystemBackup)) {
                if ((info.submissionType == CommitType::InstallerCommit) &&
                    (info.recoveryType == static_cast<int> (RecoveryType::ImmutableMode))) {
                    info.remark = tr("Initial backup during system installation");
                    info.systemVersion = tr("Initial backup");
                }
            }
            sysBackupList.append(info);
        }
        m_backupFileManagerDialog->setSystemBackupInfoData(sysBackupList);
    }

    m_backupFileManagerDialog->showToCenter();
}

void MainWindow::onError(const QString &msg)
{
    QJsonObject jsonObject = Utils::QStringToJson(msg);
    if (jsonObject.isEmpty()) {
        return;
    }

    int opType = static_cast<int> (OperateType::Invalid);
    if (jsonObject.contains("operateType")) {
        opType = jsonObject.value("operateType").toInt(-1);
    }

    if (static_cast<int> (OperateType::removeBackup) == opType) {
        QString initBackupErr = tr("File deletion error: the backup file cannot be deleted.");
        QString operateId;
        if (jsonObject.contains("operateId")) {
            operateId = jsonObject.value("operateId").toString();
        }

        QString errMsg = tr("Unkown Error");
        if (jsonObject.contains("errMsg")) {
            errMsg = jsonObject.value("errMsg").toString();
        }

        if (jsonObject.contains("OStreeState")) {
            int state = jsonObject.value("OStreeState").toInt();
            errMsg = this->getErrorMsgByErrorCode(state);
        }

        if (errMsg.contains("cannot delete the initial snapshot")) {
            errMsg = initBackupErr;
        }
        m_backupFileManagerDialog->showErrorDlg(errMsg);

        if (!operateId.isEmpty()) {
            m_backupFileManagerDialog->setDeleteWidgetStatus(true, false, operateId);
        }
    }
}

void MainWindow::onModuleChange(QAbstractButton *button)
{

    ModuleInterface *inter = m_modules.at(m_buttonBox->id(button));

    //有数据  并且最后一个和现在点击的一致
    if (!m_contentStack.isEmpty() && m_contentStack.last().first == inter) {
        return;
    }
    inter->active();
}

void MainWindow::onBackWardClick()
{
    if (m_contentStack.size() < 2) {
        return;
    }

    auto curWidget = m_contentStack.top().second;
    if (nullptr != curWidget) {
        if (curWidget->accessibleDescription() == "ResultWidget") {
            this->backHome();
            return;
        }
    }

    popWidget();
    auto topModule = m_contentStack.top().first;
    if (topModule->name() == "BackupModule") {
        m_buttonBox->button(BACKUP_BUTTON_ID)->setChecked(true);
    } else if (topModule->name() == "RestoreModule") {
        m_buttonBox->button(RESTORE_BUTTON_ID)->setChecked(true);
    } else {
        m_buttonBox->button(ADVANCED_BUTTON_ID)->setChecked(true);
    }

    auto topWidget = m_contentStack.top().second;
    if (topWidget != nullptr) {
        m_centralLayout->addWidget(m_contentStack.top().second);
        topWidget->setFocus();
        topWidget->show();
    }
}

void MainWindow::initAllModule()
{
    const int selinuxEnforcing = 1;
    int selinuxMode = -1;
    int seRetCode = selinux_getenforcemode(&selinuxMode);
    if (is_selinux_enabled() && (0 == seRetCode && selinuxEnforcing == selinuxMode)) {
        m_isSelinuxEnabled = true;
    }

    QSettings settings("/usr/lib/deepin/desktop-version", QSettings::IniFormat);
    settings.beginGroup("Release");
    const QString &osType = settings.value("Type", "Professional").toString();
    settings.endGroup();
    if ("Device" == osType) {
        m_isDevice = true;
    }

    QString fstabFile = "/etc/fstab";
    FSTabInfoList fstabList = FSTab::getFSTabFromFile(fstabFile);
    QStringList sysDeviceUuidList = FSTab::getUuidListFromFstab(fstabList);
    DeviceInfoList fileCryptDevList;
    m_isLVMOnly = Device::isLVM(sysDeviceUuidList, m_isEncrypted, m_isFileMgrEncrypted, fileCryptDevList);
    m_isSupportV20BackupRestore = Common::isSupportV20BackupAndRestore();

    m_interface = new ComDeepinDaemonUosrecoveryInterface(
            RecoveryServiceName,
            RecoveryServicePath,
            QDBusConnection::systemBus());
    m_interface->setTimeout(600000);

    m_backupModule = new BackupModule(this, m_interface);
    m_backupModule->initialize();
    m_backupModule->setDevice(m_isDevice);
    m_backupModule->setSelinuxEnable(m_isSelinuxEnabled);
    m_backupModule->setEncrypted(m_isEncrypted);
    m_backupModule->setLVM(m_isLVMOnly);
    m_backupModule->setSupportV20BackupRestore(m_isSupportV20BackupRestore);
    m_backupModule->setFileMgrEncrypted(m_isFileMgrEncrypted);
    m_backupModule->setMajorVersion(m_osMajorVer);
    m_backupModule->setMinorVersion(m_osMinorVer);
    m_modules.append(m_backupModule);

    m_restoreModule = new RestoreModule(this, m_interface);
    m_restoreModule->initialize();
    m_restoreModule->setDevice(m_isDevice);
    m_restoreModule->setSelinuxEnable(m_isSelinuxEnabled);
    m_restoreModule->setEncrypted(m_isEncrypted);
    m_restoreModule->setLVM(m_isLVMOnly);
    m_restoreModule->setSupportV20BackupRestore(m_isSupportV20BackupRestore);
    m_restoreModule->setFileMgrEncrypted(m_isFileMgrEncrypted);
    m_restoreModule->setMajorVersion(m_osMajorVer);
    m_restoreModule->setMinorVersion(m_osMinorVer);
    m_modules.append(m_restoreModule);

    m_advancedModule = new AdvancedModule(this, m_interface);
    m_advancedModule->initialize();
    m_advancedModule->setSelinuxEnable(m_isSelinuxEnabled);
    m_advancedModule->setEncrypted(m_isEncrypted);
    m_advancedModule->setLVM(m_isLVMOnly);
    m_modules.append(m_advancedModule);

    if (!m_modules.isEmpty()) {
        m_modules.at(BACKUP_BUTTON_ID)->active();
        m_buttonBox->buttonList().at(BACKUP_BUTTON_ID)->setChecked(true);
    }

    bool isInLiveCD = Common::isLiveCD();
    if (isInLiveCD) {
        DDialog dialog(this);
        dialog.setMessage(tr("The current environment is live system, can not use backup and restore tools."));
        dialog.addButton(tr("Cancel", "button"));
        dialog.setIcon(QIcon::fromTheme("dialog-warning"));
        QRect rect = geometry();
        dialog.move(rect.center());
        dialog.moveToCenter();

        int result = dialog.addButton(tr("Exit", "button"), true, DDialog::ButtonWarning);
        dialog.setAccessibleName("MainWindow_liveCDDialog");
        dialog.getButton(0)->setAccessibleName("MainWindow_liveCDDialogCancel");
        dialog.getButton(1)->setAccessibleName("MainWindow_liveCDDialogExit");
        int errCode = dialog.exec();
        if (errCode == result || -1 == errCode || 0 == errCode) {
            QApplication::exit(0);
        }
        QApplication::quit();
        return;
    }

    //必须要获取rootUUID, 如果rootUUID为空则说明运行于live系统中，需要用户指定根分区
    auto rootReply = m_interface->GetRootUUID();
    rootReply.waitForFinished();
    if (!rootReply.isValid()) {
        qCritical() << Q_FUNC_INFO << rootReply.error()<<", exit now !";
        QApplication::exit(0);
        QApplication::quit();
        return;
    }
    m_rootUUID = rootReply.value();
    if (m_rootUUID.isEmpty()) {
        DDialog dialog(this);
        dialog.setMessage(tr("It is not recommended to run this tool in the live system"));
        dialog.addButton(tr("Cancel", "button"));
        dialog.setIcon(QIcon::fromTheme("dialog-warning"));
        QRect rect = geometry();
        dialog.move(rect.center());
        dialog.moveToCenter();

        int result = dialog.addButton(tr("Exit", "button"), true, DDialog::ButtonWarning);
        dialog.setAccessibleName("MainWindow_liveSysDialog");
        dialog.getButton(0)->setAccessibleName("MainWindow_liveSysDialogCancel");
        dialog.getButton(1)->setAccessibleName("MainWindow_liveSysDialogExit");
        if (dialog.exec() == result) {
            QApplication::exit(0);
        }
        QApplication::quit();
        return;
    }

    auto currDestReply = m_interface->GetBackupDeviceUUID(m_rootUUID);
    currDestReply.waitForFinished();
    if (!currDestReply.isValid()) {
        qCritical() << Q_FUNC_INFO << "GetBackupDeviceUUID failed!, error:"<<currDestReply.error();
        return;
    }
    m_destUUID = currDestReply.value();

    ErrorCode retCode = initRecoveryType();
    if (retCode != ErrorCode::OK) {
        qCritical() << Q_FUNC_INFO << ", initRecoveryType failed, retCode = " << retCode;
        DDialog dialog(this);
        dialog.setMessage(tr("This app does not work for your system, as it only supports ext4, btrfs and xfs file systems."));
        dialog.setIcon(QIcon::fromTheme("dialog-warning"));
        QRect rect = geometry();
        dialog.move(rect.center());
        dialog.moveToCenter();

        int result = dialog.addButton(tr("Exit", "button"), true, DDialog::ButtonWarning);
        dialog.setAccessibleName("MainWindow_appNotSupportDialog");
        dialog.getButton(0)->setAccessibleName("MainWindow_appNotSupportDialogCancel");
        dialog.getButton(1)->setAccessibleName("MainWindow_appNotSupportDialogExit");
        int errCode = dialog.exec();
        if (errCode == result || -1 == errCode) {
            QApplication::exit(0);
        }
        return;
    }

    connect(m_interface, &ComDeepinDaemonUosrecoveryInterface::ReportCheckSpace, this, &MainWindow::onCheckSpace);
}

void MainWindow::setMenuDisabled(bool disabled)
{
    DTitlebar *titleBar = this->titlebar();
    if (nullptr != titleBar) {
        titleBar->setMenuDisabled(disabled);
    }
}

void MainWindow::setQuitMenuDisabled(bool disabled)
{
    DTitlebar *titleBar = this->titlebar();
    if (nullptr != titleBar) {
        titleBar->setQuitMenuDisabled(disabled);
    }
}

void MainWindow::setMenuActionEnabled(const QString &actionText, bool enabled)
{
    DTitlebar *titleBar = this->titlebar();
    if (nullptr != titleBar) {
        QList<QAction*> actionList = titleBar->menu()->actions();
        auto itAction = std::find_if(actionList.begin(), actionList.end(), [=](const QAction *action) {
                return (actionText == action->text());
            });
        if (itAction != actionList.end()) {
            (*itAction)->setEnabled(enabled);
        }
    }
}

void MainWindow::setWindowFuncClose(bool enabled)
{
    DWindowManagerHelper::instance()->setMotifFunctions(windowHandle(), DWindowManagerHelper::FUNC_CLOSE, enabled);
    DTitlebar *titleBar = this->titlebar();
    if (nullptr != titleBar) {
        if (enabled) {
            auto flags = windowFlags();
            auto newFlags = flags &~ Qt::WindowCloseButtonHint &~ Qt::WindowMinimizeButtonHint;
            titleBar->setDisableFlags(newFlags);
        } else {
            titleBar->setDisableFlags(Qt::WindowCloseButtonHint);
        }
    }
}

ErrorCode MainWindow::initRecoveryType()
{
    if (m_interface == nullptr) {
    //    qCritical() << Q_FUNC_INFO << ", m_interface is null";
        return ErrorCode::NullPointer;
    }

    auto initReply = m_interface->AutoInitSystemRecoveryType(m_rootUUID);
    initReply.waitForFinished();
    if (!initReply.isValid()) {
        qCritical() << Q_FUNC_INFO << initReply.error();
        return ErrorCode::DbusError;
    }

    int retCode = initReply.value();
    if (retCode != static_cast<int> (ErrorCode::OK)) {
        qCritical() << Q_FUNC_INFO << "AutoInitSystemRecoveryType failed, retCode = " << retCode;
        return static_cast<ErrorCode> (retCode);
    }

    auto systemSyncTypeReply = m_interface->GetSystemSyncType();
    systemSyncTypeReply.waitForFinished();
    if (!systemSyncTypeReply.isValid()) {
        qCritical() << Q_FUNC_INFO << ", GetSystemSyncType failed: "<< systemSyncTypeReply.error();
        return ErrorCode::DbusError;
    }

    if (nullptr != m_backupModule) {
        m_backupModule->setSystemSyncType(systemSyncTypeReply.value());
    }

    if (nullptr != m_restoreModule) {
        m_restoreModule->setSystemSyncType(systemSyncTypeReply.value());
    }

    auto userDataSyncTypeReply = m_interface->GetUserDataSyncType();
    userDataSyncTypeReply.waitForFinished();
    if (!userDataSyncTypeReply.isValid()) {
        qCritical() << Q_FUNC_INFO << ", GetUserDataSyncType failed: "<< userDataSyncTypeReply.error();
        return ErrorCode::DbusError;
    }

    m_backupModule->setUserDataSyncType(userDataSyncTypeReply.value());
    m_restoreModule->setUserDataSyncType(userDataSyncTypeReply.value());

    return ErrorCode::OK;
}

void MainWindow::onCheckSpace(const QString &space)
{
    QJsonObject jsonObject = Utils::QStringToJson(space);
    int recoveryType = -1;
    if (jsonObject.contains("recoveryType")) {
        recoveryType = jsonObject.value("recoveryType").toInt(-1);
    }

    if (recoveryType != static_cast<int> (RecoveryType::Rsync)) {
        return;
    }

    int errorCode = -1;
    if (jsonObject.contains("errCode")) {
        errorCode = jsonObject.value("errCode").toInt(-1);
    }

    int operateType = -1;
    if (jsonObject.contains("operateType")) {
        operateType = jsonObject.value("operateType").toInt(-1);
    }

    if (operateType == static_cast<int> (OperateType::CheckFullSystemBackupSpace) ||
        operateType == static_cast<int> (OperateType::CheckIncSystemBackupSpace)) {
        if (m_selectPartitionDialog != nullptr) {
            m_selectPartitionDialog->onShowResult(errorCode);
        }

        if (errorCode == OK) {
            if (operateType == static_cast<int> (OperateType::CheckFullSystemBackupSpace)) {
                auto setDestReply = m_interface->SetBackupDeviceUUID(m_currDestUUID);
                setDestReply.waitForFinished();
                if (!setDestReply.isValid()) {
                    qCritical() << Q_FUNC_INFO<<" SetBackupDeviceUUID failed! "<<setDestReply.error();
                    return;
                }
                this->updateDestPartition();
            }
        }
    }
}

void MainWindow::updateDestPartition()
{
    m_destUUID = m_currDestUUID;
    if (m_backupModule != nullptr) {
        m_backupModule->updateDestPartition(m_destPartitionJson);
    }

    if (m_selectPartitionDialog != nullptr) {
        m_selectPartitionDialog->setDestUUID(m_currDestUUID);
    }
}

void MainWindow::ShowBackupPage()
{
    if (!m_modules.isEmpty()) {
        bool isRun = m_interface->IsRunning();
        if (!isRun) {
            auto module = m_modules.at(BACKUP_BUTTON_ID);
            if (nullptr != module) {
                module->active();
            }
            auto item = m_buttonBox->buttonList().at(BACKUP_BUTTON_ID);
            if (nullptr != item) {
                item->setChecked(true);
            }
        }

        this->raise();
        if (this->isMinimized() || !this->isVisible()) {
            this->showNormal();
        }
        this->activateWindow();
    }
}

void MainWindow::ShowRestorePage()
{
    if (!m_modules.isEmpty()) {
        bool isRun = m_interface->IsRunning();
        if (!isRun) {
            auto module = m_modules.at(RESTORE_BUTTON_ID);
            if (nullptr != module) {
                module->active();
            }
            auto item = m_buttonBox->buttonList().at(RESTORE_BUTTON_ID);
            if (nullptr != item) {
                item->setChecked(true);
            }
        }

        this->raise();
        if (this->isMinimized() || !this->isVisible()) {
            this->showNormal();
        }
        this->activateWindow();
    }
}

void MainWindow::ShowSystemClonePage()
{
    if (!m_modules.isEmpty()) {
        bool isRun = m_interface->IsRunning();
        if (!isRun) {
            auto module = m_modules.at(ADVANCED_BUTTON_ID);
            if (nullptr != module) {
                module->active();
            }
            auto item = m_buttonBox->buttonList().at(ADVANCED_BUTTON_ID);
            if (nullptr != item) {
                item->setChecked(true);
            }
        }

        this->raise();
        if (this->isMinimized() || !this->isVisible()) {
            this->showNormal();
        }
        this->activateWindow();
    }
}
