/*
 * 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 <http://www.gnu.org/licenses/>.
 */
#include "upmcpucontrol.h"

#include <QDebug>
#include <QThread>

UpmCpuControl::UpmCpuControl(QObject *parent) : QObject(parent)
{
    m_cpuCoreNum = QThread::idealThreadCount();
    qDebug() << "m_cpuCoreNum :" << m_cpuCoreNum;

    m_maxCpuOnlineCore = m_cpuCoreNum - 1;
    m_cpuOnlineCore = m_maxCpuOnlineCore;

    for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) {
        m_allCpuCoreInfo.push_back(new UpmCpuCoreInfo(cpuCoreNum, this));
    }

    initSystemIdleReserveCpu0();

    initBalanceModeLimitCpuFreq();

    initAutoSwitchCpuCore();
}

void UpmCpuControl::initSystemIdleReserveCpu0()
{
    m_idleReserveCpu0[Performance] = false;
    m_idleReserveCpu0[Balance] = false;
    m_idleReserveCpu0[Powersave] = false;

    QStringList configKeys = {UPM_KEY_EXTEND_PERFORMANCE_IDEL_RESERVE_CPU0,
                              UPM_KEY_EXTEND_BALANCE_IDEL_RESERVE_CPU0,
                              UPM_KEY_EXTEND_POWERSAVE_IDEL_RESERVE_CPU0};
    QString config;
    for (int policy = Performance; policy < max_policy; ++policy) {
        if (true == UpmCustomHardwareConfig::self()->getExtendConfig(configKeys[policy], config)) {
            if (1 == config.toInt()) {
                m_idleReserveCpu0[policy] = true;
            }
        }
    }
}

void UpmCpuControl::initBalanceModeLimitCpuFreq()
{
    QString config;
    if (true == UpmCustomHardwareConfig::self()->getExtendConfig(
                UPM_KEY_EXTEND_BALANCE_MODE_REDUCE_FREQUENCY, config)) {
        if (1 == config.toInt()) {
            m_balanceModeSetMaxFreq = true;
        }
    }

    if (true == UpmCustomHardwareConfig::self()->getExtendConfig(
                UPM_KEY_EXTEND_BALANCE_MODE_MAX_FREQUENCY, config)) {
        m_balanceMaxCpuFrequency = config.toInt();
    }
}

void UpmCpuControl::initAutoSwitchCpuCore()
{
    m_cpuOccupy = new UpmCpuOccupy(this);
    connect(m_cpuOccupy, &UpmCpuOccupy::cpuCoreSwitchSignal,
            this, &UpmCpuControl::dealCpuSwitchSignal);

    for (int policy = Performance; policy < max_policy; ++policy) {
        initAutoSwitchCpuCoreConfig(policy);
    }
}

void UpmCpuControl::initAutoSwitchCpuCoreConfig(int cpuPolicy)
{
    if (cpuPolicy < Performance || cpuPolicy > Powersave) {
        return ;
    }

    QStringList configKeys = {UPM_KEY_EXTEND_PERFORMANCE_AUTO_SWITCH_CPU_CORE,
                              UPM_KEY_EXTEND_BALANCE_AUTO_SWITCH_CPU_CORE,
                              UPM_KEY_EXTEND_POWERSAVE_AUTO_SWITCH_CPU_CORE};

    m_configs[cpuPolicy].configActive = false;
    m_configs[cpuPolicy].cpuSamplingInterval = 30000;
    m_configs[cpuPolicy].offlineCpuOccupy = 50;
    m_configs[cpuPolicy].onlineCpuOccupy = 70;
    m_configs[cpuPolicy].reserveCoreNum = m_cpuCoreNum / 2;

    QString config;
    m_configs[cpuPolicy].configActive =
            UpmCustomHardwareConfig::self()->getExtendConfig(configKeys[cpuPolicy], config);
    if (true == m_configs[cpuPolicy].configActive) {
        QStringList configs = config.split("-");
        if (max_auto_switch_cpu_core_config == configs.size()) {
            m_configs[cpuPolicy].cpuSamplingInterval = configs[cpu_sampling_interval].toInt();
            m_configs[cpuPolicy].offlineCpuOccupy = configs[offline_cpu_occupy].toInt();
            m_configs[cpuPolicy].onlineCpuOccupy = configs[online_cpu_occupy].toInt();
            m_configs[cpuPolicy].reserveCoreNum = configs[reserve_core_num].toInt();
            if (0 == m_configs[cpuPolicy].reserveCoreNum) {
                m_configs[cpuPolicy].reserveCoreNum = 1;
            }
        } else {
            m_configs[cpuPolicy].configActive = false;
        }
    }
}

int UpmCpuControl::getCpuCoreNum()
{
    return m_cpuCoreNum;
}

void UpmCpuControl::setCorePolicy(int cpuCoreId, int cpuPolicy)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return ;
    }
    m_allCpuCoreInfo[cpuCoreId]->setCorePolicy(cpuPolicy);
}

QString UpmCpuControl::getCpuCorePolicy(int cpuCoreId)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return "cpu core id failed";
    }
    return m_allCpuCoreInfo[cpuCoreId]->getCpuCorePolicy();
}

void UpmCpuControl::setCoreMaxFreq(int cpuCoreId, int cpuFrequency)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return ;
    }
    m_allCpuCoreInfo[cpuCoreId]->setCoreMaxFreq(cpuFrequency);
}

int UpmCpuControl::getDefaultCoreMaxFreq(int cpuCoreId)
{
    return m_allCpuCoreInfo[cpuCoreId]->getDefaultCoreMaxFreq();
}

void UpmCpuControl::setCoreDefaultMaxFreq(int cpuCoreId)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return ;
    }
    m_allCpuCoreInfo[cpuCoreId]->setDefaultCoreMaxFreq();
}

void UpmCpuControl::setAllCorePolicy(int cpuPolicy)
{
    if (cpuPolicy < Performance || cpuPolicy > Powersave) {
        return ;
    }

    m_cpuPolicy = cpuPolicy;

    m_cpuOccupy->stopCalcCpuOccupy();

    for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) {
        setCpuCoreOnlineState(cpuCoreNum, cpu_core_online);
        if (true == m_balanceModeSetMaxFreq) {
            if (Balance == m_cpuPolicy) {
                if (0 == m_balanceMaxCpuFrequency) {
                    setCoreMaxFreq(cpuCoreNum, getDefaultCoreMaxFreq(cpuCoreNum) * 0.8);
                } else {
                    setCoreMaxFreq(cpuCoreNum, m_balanceMaxCpuFrequency);
                }
            } else {
                setCoreDefaultMaxFreq(cpuCoreNum);
            }
        }
        m_allCpuCoreInfo[cpuCoreNum]->setCorePolicy(m_cpuPolicy);
    }
    m_cpuOnlineCore = m_maxCpuOnlineCore;

    if (true == m_configs[m_cpuPolicy].configActive) {
        m_cpuOccupy->startCalcCpuOccupy(m_configs[m_cpuPolicy].cpuSamplingInterval,
                                        m_configs[m_cpuPolicy].offlineCpuOccupy,
                                        m_configs[m_cpuPolicy].onlineCpuOccupy);
    }
}

void UpmCpuControl::setAllCoreMaxFreq(int cpuFrequency)
{
    for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) {
        m_allCpuCoreInfo[cpuCoreNum]->setCoreMaxFreq(cpuFrequency);
    }
}

void UpmCpuControl::setAllCoreDefaultMaxFreq()
{
    for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) {
        m_allCpuCoreInfo[cpuCoreNum]->setDefaultCoreMaxFreq();
    }
}

int UpmCpuControl::getCpuCoreOnlineState(int cpuCoreId)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return cpu_core_error;
    }
    return m_allCpuCoreInfo[cpuCoreId]->getCpuCoreOnlineState();
}

void UpmCpuControl::setCpuCoreOnlineState(int cpuCoreId, int online)
{
    if (cpuCoreId >= m_cpuCoreNum) {
        return ;
    }
    if (0 == cpuCoreId) {
        return ;
    }

    m_allCpuCoreInfo[cpuCoreId]->setCpuCoreOnlineState(online);
}

void UpmCpuControl::systemIdleReserveCpu0(bool systmIdle)
{
    qDebug() << "systemIdleReserveCpu0 :" << systmIdle;
    if (true == systmIdle) {
        //系统进入空闲，不在通过计算cpu占用率控制开关核心，停止用于计算cpu占用率的定时器
        m_cpuOccupy->stopCalcCpuOccupy();
        qDebug() << "m_cpuPolicy :" << m_cpuPolicy << "idleReserveCpu0 :" << m_idleReserveCpu0[m_cpuPolicy];
        if (true == m_idleReserveCpu0[m_cpuPolicy]) {
            qDebug() << "1 m_cpuOnlineCore :" << m_cpuOnlineCore;
            //空闲时，仅保留一个cpu核心的功能enable，关闭其他核心
            while (m_cpuOnlineCore > 0) {
                qDebug() << "cpu core offline :" << m_cpuOnlineCore;
                setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_offline);
                m_cpuOnlineCore--;
            }
        } else {
            qDebug() << "2 m_cpuOnlineCore :" << m_cpuOnlineCore;
            //空闲时，仅保留一个cpu核心的功能disable，开启以关闭的核心
            while (m_cpuOnlineCore < m_maxCpuOnlineCore) {
                m_cpuOnlineCore++;
                qDebug() << "cpu core online :" << m_cpuOnlineCore;
                setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online);
            }
        }
    } else {
        //非空闲状态，开启所有的cpu核心
        qDebug() << "3 m_cpuOnlineCore :" << m_cpuOnlineCore;
        while (m_cpuOnlineCore < m_maxCpuOnlineCore) {
            m_cpuOnlineCore++;
            qDebug() << "cpu core online :" << m_cpuOnlineCore;
            setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online);
        }

        if (true == m_configs[m_cpuPolicy].configActive) {
            qDebug() << "cpu policy :" << m_cpuPolicy << "start calc cpu occupy";
            //非空闲状态，动态开关核心功能enable，重新打开计算cpu占用率的定时器
            m_cpuOccupy->startCalcCpuOccupy(m_configs[m_cpuPolicy].cpuSamplingInterval,
                                            m_configs[m_cpuPolicy].offlineCpuOccupy,
                                            m_configs[m_cpuPolicy].onlineCpuOccupy);
        }
    }
}

void UpmCpuControl::enableBalanceModeFrequency(bool enable)
{
    m_balanceModeSetMaxFreq = enable;
}

void UpmCpuControl::enableSystemIdleReserveCpu0(bool enable, int cpuPolicy)
{
    m_idleReserveCpu0[cpuPolicy] = enable;
}

void UpmCpuControl::enableAutoSwitchCpuCore(bool enable, int cpuPolicy)
{
    if (cpuPolicy < Performance || cpuPolicy > Powersave) {
            return ;
        }
    m_configs[cpuPolicy].configActive = enable;
}

void UpmCpuControl::dealCpuSwitchSignal(bool coreOnline)
{
    if (true == coreOnline) {
        if (m_cpuOnlineCore < m_maxCpuOnlineCore) {
            m_cpuOnlineCore++;
            setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online);
        }
    } else {
        if (m_cpuOnlineCore >= m_configs[m_cpuPolicy].reserveCoreNum) {
            setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_offline);
            m_cpuOnlineCore--;
        }
    }
}



