/*
 * Copyright 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/>.
 */

#include "appcgroup.h"
#include <QDBusPendingReply>
#include <QDebug>
#include <unistd.h>

AppCGroup::AppCGroup(QObject *parent) 
    : QObject(parent)
    , m_processManagerInterface(new com::kylin::ProcessManager("com.kylin.ProcessManager", 
                                "/com/kylin/ProcessManager", QDBusConnection::systemBus()))
{
    initCGroup();
}

QString AppCGroup::createProcessCGroup(const QString &appId, const QList<int> &pids)
{
    auto reply = m_processManagerInterface->CreateProcessCGroup(appId, pids);
    qDebug() << "reply is finished. " << reply.isFinished();
    while (!reply.isFinished()) {
        qApp->processEvents();
        usleep(10);
    }
    if (reply.isError()) {
        qWarning() << "createProcessCGroup error, " << reply.error();
        return QString();
    }

    if (reply.value().value(kDbusResult).toString().isEmpty()) {
        qWarning() << "createProcessCGroup error, " << reply.value().value(kDbusErrMsg).toString();
        return QString();
    }
    return reply.value().value(kDbusResult).toString();
}

bool AppCGroup::deleteProcessCGroup(const QString &cgroupName)
{
    auto reply = m_processManagerInterface->DeleteProcessCGroup(cgroupName);
    return true;   
}

bool AppCGroup::setProcessCGroupResourceLimit(const QString &cgroupName,
                                              const QString &attrName,
                                              int value)
{
    auto reply = m_processManagerInterface->SetProcessCGroupResourceLimit(cgroupName, attrName, value);
    return true; 
}

bool AppCGroup::reclaimProcesses(const QList<int> &pids)
{
    auto reply = m_processManagerInterface->ReclaimProcesses(pids);
    return true;   
}

bool AppCGroup::reclaimProcesses(const QString &cgroupName)
{
    auto reply = m_processManagerInterface->ReclaimProcesses(cgroupName);
    return true; 
}

QString AppCGroup::cgroupNameWithPid(int pid)
{
    auto reply = m_processManagerInterface->CGroupNameWithPid(pid);
    while (!reply.isFinished()) {
        qApp->processEvents();
        usleep(1);
    }
    if (reply.isError()) {
        qWarning() << __FUNCTION__ << "error, " << reply.error();
        return QString();
    }
    return reply.value().value(kDbusResult).toString();
}

void AppCGroup::initCGroup()
{
    QProcess p;
    p.start("id", QStringList() << "-u");
    p.waitForFinished();
    auto userId = p.readAll().toUInt();
    auto rootPath = QString("user.slice/user-%1.slice/kylin-app-manager").arg(userId);
    auto reply = m_processManagerInterface->InitCGroup(rootPath);
    while (!reply.isFinished()) {
        qApp->processEvents();
        usleep(1);
    }
    if (reply.isError()) {
        qWarning() << __FUNCTION__ << "error, " << reply.error();
        return;
    }
    if (!reply.value().value(kDbusResult).toBool()) {
        qWarning() << "Init CGroup failed, " 
                   << reply.value().value(kDbusErrMsg).toString()
                   << "the root path is " << rootPath;
    }
    qDebug() << reply.value().value(kDbusResult) << rootPath;
}
