/*
 * 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 "resourcemanagerinterface.h"
#include "loghelper.h"
#include "misc.h"
#include <QDebug>

void ResourceManagerInterface::createPersistentProcessGroup(
    const std::string &path, const std::vector<std::string> &cgroupControllers)
{
    if (misc::version::cgroupVersion() == 1) {
        m_daemonDbus.createProcessGroup(path, cgroupControllers, std::vector<int>{});
    } else if (misc::version::cgroupVersion() == 2) {
        if (path.find("system.slice") != std::string::npos){
            m_daemonDbus.createProcessGroup(path, cgroupControllers, std::vector<int>{});
        } else {
            m_systemdDbus.createPersistentProcessGroup(getGroupNameFromPath(path));
        }
    }
}

void ResourceManagerInterface::createTransientProcessGroup(
    const std::string &path, const std::vector<int> &pids,
    const std::vector<std::string> &cgroupControllers)
{
    if (misc::version::cgroupVersion() == 1 || path.find("system.slice") != std::string::npos) {
        m_daemonDbus.createProcessGroup(path, cgroupControllers, pids);
    }
    m_systemdDbus.createTransientProcessGroup(
        getGroupNameFromPath(path), pids, getGroupParentSliceFromPath(path));
}

void ResourceManagerInterface::setProcessGroupResourceLimit(
    const std::string &attributeName,
    const std::string &path, const std::string &controller,
    const std::string &file, const std::string &value)
{
    if (misc::version::cgroupVersion() == 1 || path.find("system.slice") != std::string::npos) {
        m_daemonDbus.setProcessGroupResourceLimit(path, controller, file, value);
    } else if (misc::version::cgroupVersion() == 2) {
        const std::string unitName = getGroupNameFromPath(path);
        m_systemdDbus.setProcessGroupResourceLimit(
            unitName, attributeName, value);
    }
}

void ResourceManagerInterface::moveProcessToGroup(
    const std::string &path, const std::vector<std::string> &controllers,
    const std::vector<int> &pids)
{
    m_daemonDbus.moveProcessToGroup(path, controllers, pids);
}

void ResourceManagerInterface::removeProcessGroup(const std::string &path, bool recursive, bool ignoreMigration)
{
    m_daemonDbus.removeProcessGroup(path, recursive, ignoreMigration);
}

void ResourceManagerInterface::moveProcessGroupToRoot(const std::string &path, const std::vector<std::string> &cgroupControllers)
{
    m_daemonDbus.moveProcessGroupToRoot(path, cgroupControllers); 
}

void ResourceManagerInterface::moveProcessPidToGroup(const std::string &path, const std::vector<std::string> &controllers, 
    const std::vector<int> &pids)
{
    m_daemonDbus.moveProcessPidToGroup(path, controllers, pids); 
}

void ResourceManagerInterface::setCurrentUserServiceUnitPropertyEnabled(
    const std::string &property, bool enabled)
{
    const auto &currentUserService = m_systemdDbus.currentUserServiceName();
    m_daemonDbus.setSystemdUnitPropertyEnabled(currentUserService, property, enabled);
}

void ResourceManagerInterface::reclaimProcessGroups(const std::vector<std::string> &groupNames)
{
    m_daemonDbus.reclaimProcessGroups(groupNames);
}

void ResourceManagerInterface::openPSR()
{
    PRINT_DBG("ResourceManagerInterface::openPSR()\n");
    m_daemonDbus.openPSR();
}

void ResourceManagerInterface::closePSR()
{
    PRINT_DBG("ResourceManagerInterface::closePSR()\n");
    m_daemonDbus.closePSR();
}

void ResourceManagerInterface::setVRRRefreshRate(std::string mode) 
{
    PRINT_DBG("ResourceManagerInterface::setVRRRefreshRate()\n");
    m_daemonDbus.setVRRRefreshRate(mode);
}

void ResourceManagerInterface::reverseVRRRefreshRate()
{
    PRINT_DBG("ResourceManagerInterface::reverseVRRRefreshRate()\n");
    m_daemonDbus.reverseVRRRefreshRate();
}

void ResourceManagerInterface::setSystemdUnitRun(const std::string &unitName, bool start, bool mode)
{
    if (mode) {
        m_daemonDbus.setSystemdUnitRun(unitName, start);
    } else {
        m_systemdDbus.setSystemdUnitRun(QString::fromStdString(unitName), start, 0);
    }
}

void ResourceManagerInterface::setSystemdUnitFreezelimit(const std::string &unitName, bool freeze, bool mode)
{
    if (mode) {
        m_daemonDbus.setSystemdUnitFreezelimit(unitName, freeze);
    } else {
        m_systemdDbus.setSystemdUnitFreezelimit(QString::fromStdString(unitName), freeze, false);
    }
}

int ResourceManagerInterface::getSystemdUnitMainpid(const std::string &unitName, bool mode)
{
    return m_systemdDbus.getServiceMainpid(QString::fromStdString(unitName), mode);
}

void ResourceManagerInterface::setCurrentScene(const std::vector<std::string> &currScenes)
{
    return m_daemonDbus.setCurrentScene(currScenes);
}

void ResourceManagerInterface::SetSystemCpuFreq(bool cpufreq)
{
    PRINT_DBG("ResourceManagerInterface::SetSystemCpuFreq()\n");
    m_daemonDbus.setSystemCpuFreq(cpufreq);
}

void ResourceManagerInterface::SetSamplingRate(bool samplingrate)
{
    PRINT_DBG("ResourceManagerInterface::SetSamplingRate()\n");
    m_daemonDbus.SetSamplingRate(samplingrate);
}

void ResourceManagerInterface::SetKernelSched(bool kernelsched)
{
    PRINT_DBG("ResourceManagerInterface::SetKernelSched()\n");
    m_daemonDbus.SetKernelSched(kernelsched);
}

void ResourceManagerInterface::SetDirty(bool dirty)
{
    PRINT_DBG("ResourceManagerInterface::SetDirty()\n");
    m_daemonDbus.SetDirty(dirty);
}

void ResourceManagerInterface::SetNetParams(bool netparams)
{
    PRINT_DBG("ResourceManagerInterface::SetNetParams()\n");
    m_daemonDbus.SetNetParams(netparams);
}

void ResourceManagerInterface::SetCpuLimit(bool cpulimit)
{
    PRINT_DBG("ResourceManagerInterface::SetCpuLimit()\n");
    m_daemonDbus.SetCpuLimit(cpulimit);
}

std::string ResourceManagerInterface::getGroupNameFromPath(const std::string &path) const
{
    auto stringList = misc::string::split(path, '/');
    if (stringList.empty()) {
        return std::string();
    }

    return stringList.back();
}

std::string ResourceManagerInterface::getGroupParentSliceFromPath(const std::string &path) const
{
    auto stringList = misc::string::split(path, '/');
    if (stringList.size() < 2) {
        return std::string();
    }

    return stringList.at(stringList.size() - 2);
}
