/*
 * Copyright 2021 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 "sysdbusregister.h"

#include <QDebug>


SysdbusRegister::SysdbusRegister()
{
    m_powerConfig = new PowerConfig(this);

    m_brightnessNode = new BrightnessNode(this);

    checkTlpOrigin();
    m_upmCpuControl = new UpmCpuControl(this);

    m_devPowerControl = new DevPowerControl(this);

    m_hardwarePowerControl = new HardwarePowerControl(this);

}

SysdbusRegister::~SysdbusRegister() {}

bool SysdbusRegister::CanSetBrightness()
{
    return m_brightnessNode->canSetBrightness();
}

bool SysdbusRegister::checkEnviron(int pid)
{
    QString filePath = QString("/proc/%1/environ").arg(pid);
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "file.open failed" << filePath;
        return false;
    }
    QTextStream in(&file);
    QString data = in.readAll();
    file.close();
    data.replace('\0', '\n');
    QStringList environVars = data.split('\n');
    for (const QString &var : environVars) {
        if (!var.isEmpty()) {
            int pos = var.indexOf('=');
            if (pos != -1) {
                QString key = var.left(pos);
                if (key == "LD_PRELOAD" || key == "LD_LIBRARY_PATH" || key == "LD_AUDIT") {
                    return false;
                }
            }
        }
    }
    return true;
}

qulonglong SysdbusRegister::GetMaxBrightness()
{
    if (false == m_brightnessNode->canSetBrightness()) {
        return 0;
    }

    return m_brightnessNode->getMaxBrightness();
}

qulonglong SysdbusRegister::GetBrightness()
{

    if (false == m_brightnessNode->canSetBrightness()) {
        return 0;
    }

    return m_brightnessNode->getCurrentBrightness();
}

QString SysdbusRegister::RegulateBrightness(qulonglong brightness)
{
    if (false == m_brightnessNode->canSetBrightness()) {
        return "no effective node";
    }

    m_currentBrightness = brightness;
    return m_brightnessNode->setCurrentBrightness(brightness);
}

QString SysdbusRegister::resetBrightness()
{
    if (m_currentBrightness < 0){
        return "unset";
    }
    if (false == m_brightnessNode->canSetBrightness()) {
        return "no effective node";
    }

    return m_brightnessNode->setCurrentBrightness(m_currentBrightness);
}

bool SysdbusRegister::IsBrightnessEnhancementSupported()
{
    return m_brightnessNode->isBrightnessEnhancementSupported();
}

void SysdbusRegister::CpuFreqencyModulation(int strategy)
{
    m_cpuPolicy = strategy;
    // 条件解释:
    // 1. 如果不是M900设备(false == isPanguM900()) -> 应用CPU控制
    // 2. 如果是M900但也是PWC30设备(true == isPgwDevice()) -> 应用CPU控制
    // 3. 只有在是M900且不是PWC30时 -> 跳过CPU控制
    // 使用HardwareReader
    HardwareReader *reader = HardwareReader::instance();
    if (false == reader->isPanguM900() || true == reader->isPgwDevice()) {
        m_upmCpuControl->setAllCorePolicy(strategy);
    } else {
        qInfo() << "Skipping CPU control: device is M900 but not PWC30";
    }
    // 设备电源管理对所有设备类型都应用（保持不变）
    if (Performance == strategy) {
        m_devPowerControl->setAllDevicePerformance();
    } else if (Powersave == strategy) {
        m_devPowerControl->setAllDeviceSave();
    } else {
        m_devPowerControl->setAllDeviceBalance();
    }
}

bool SysdbusRegister::FirstRunDonotSuspend()
{
    if (1 == m_powerConfig->getPowerManagerRunTimes()
    &&  true == UpmCustomHardwareConfig::self()->firstRunDonotSuspend()) {
        return true;
    }
    return false;
}

void SysdbusRegister::GpuFreqencyModulation(int strategy)
{
    m_hardwarePowerControl->setGpuFrequencyMode(strategy);
}

void SysdbusRegister::SetAudioMode(int strategy)
{
    m_hardwarePowerControl->setAudioMode(strategy);
}

void SysdbusRegister::SetPcieAspmMode(int strategy)
{
    m_hardwarePowerControl->setPcieAspmMode(strategy);
}

int SysdbusRegister::GetCpuPolicy()
{
    return m_cpuPolicy;
}

void SysdbusRegister::SystemIdleReserveCpu0(bool systemIdle)
{
    m_upmCpuControl->systemIdleReserveCpu0(systemIdle);
}

void SysdbusRegister::EnableReduceCpuFrequency(bool enable)
{
    m_upmCpuControl->enableBalanceModeFrequency(enable);
}

void SysdbusRegister::EnableSystemIdleReserveCpu0(bool enable, int cpuPolicy)
{
    m_upmCpuControl->enableSystemIdleReserveCpu0(enable, cpuPolicy);
}

void SysdbusRegister::EnableAutoSwitchCpuCore(bool enable, int cpuPolicy)
{
    m_upmCpuControl->enableAutoSwitchCpuCore(enable, cpuPolicy);
}

void SysdbusRegister::enterTlp()
{
    checkTlpOrigin();
    QProcess::startDetached(TLP_BAT_CMD);
}

void SysdbusRegister::exitTlp()
{
    checkTlpOrigin();//退出不用tlp ac是担心出现配置异常的问题。
    for (auto it = m_tlpMap.begin(); it != m_tlpMap.end(); ++it) {
        QFile qfile(it.key());
        if (!qfile.exists()) {
            continue;
        }
//        UPM_LOG(LOG_DEBUG,"write:%s=%s",it.key().toLatin1().data(), it.value().toLatin1().data());
        qfile.open(QIODevice::WriteOnly|QIODevice::Text);
        qfile.write(it.value().toLatin1().data());
        qfile.close();
    }
}

QString SysdbusRegister::printfTlpNodeValue()
{
    QFile tlpOrigin(TLP_ORIGIN_CONF);
    QString allnodes;
    QStringList nodeList;
    QString ret = "";
    if (!tlpOrigin.exists()) {
        return "";
    }

    tlpOrigin.open(QIODevice::ReadOnly|QIODevice::Text);
    allnodes = tlpOrigin.readAll();
    nodeList = allnodes.split("\n");

    Q_FOREACH (const QString str, nodeList) {
        QFile nodeFile(str);
        if (!nodeFile.exists()) {
            continue;
        }

        nodeFile.open(QIODevice::ReadOnly|QIODevice::Text);
        QString nodeValue = nodeFile.readAll();
        nodeFile.close();
        ret += str + "=" + nodeValue;
//        UPM_LOG(LOG_DEBUG,"write:%s=%s",str.toLatin1().data(), nodeValue.toLatin1().data());
    }
    return ret;
}

void SysdbusRegister::checkTlpOrigin()
{

    QFile tlpOrigin(TLP_ORIGIN_CONF);
    QFile tlpOriginConf(TLP_ORIGIN_DEFAULT_CONFIG);
    QString cmd = TLP_ORIGIN_GET_PATH_SH;

    if (tlpOriginConf.exists()) {
        readAllNodeToMap();
        return;
    }

    if (tlpOrigin.exists()) {
        genDefaultConfig();
        return;
    }

    //把可执行程序加入白名单，这样就不会有弹窗报警了。
    QProcess::startDetached(TLP_SET_WHITE_LIST);
    QProcess::startDetached(TLP_SET_WHITE_LIST1);
    QProcess::startDetached(TLP_SET_WHITE_LIST2);
    QProcess::startDetached(TLP_SET_WHITE_LIST3);
    QProcess::startDetached(TLP_SET_WHITE_LIST4);
    QProcess::startDetached(TLP_SET_WHITE_LIST5);
    QProcess::startDetached(TLP_SET_WHITE_LIST6);
    QProcess::startDetached(TLP_SET_WHITE_LIST7);
    QProcess::startDetached(TLP_SET_WHITE_LIST8);
    QProcess::startDetached(TLP_SET_WHITE_LIST9);
    QProcess::startDetached(TLP_SET_WHITE_LIST10);

    m_progress = new QProcess(this);
    connect(m_progress, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(doProcessResult(int,QProcess::ExitStatus)));
    m_progress->startDetached(cmd);
}

bool SysdbusRegister::genDefaultConfig()
{
    QFile tlpOrigin(TLP_ORIGIN_CONF);
    QString allnodes;
    QStringList nodeList;

    if (!tlpOrigin.exists()) {
        return false;
    }

    tlpOrigin.open(QIODevice::ReadOnly|QIODevice::Text);
    allnodes = tlpOrigin.readAll();
    nodeList = allnodes.split("\n");
    m_tlpMap.clear();

    Q_FOREACH (const QString str, nodeList) {
        QFile nodeFile(str);
        if (!nodeFile.exists()) {
            continue;
        }

        nodeFile.open(QIODevice::ReadOnly|QIODevice::Text);
        QString nodeValue = nodeFile.readAll();
        if (str.contains("energy_performance_preference") && nodeValue.contains("power")) {
            //error,异常数据不进行备份。
            return false;
        }
        nodeFile.close();
        m_tlpMap.insert(str, nodeValue.replace("\n",""));
    }
    tlpOrigin.close();

    QSettings settings(TLP_ORIGIN_DEFAULT_CONFIG, QSettings::NativeFormat);
    for (auto it = m_tlpMap.begin(); it != m_tlpMap.end(); ++it) {
        settings.setValue(it.key(), it.value());
    }
    return true;
}

bool SysdbusRegister::readAllNodeToMap()
{
     QSettings settings(TLP_ORIGIN_DEFAULT_CONFIG, QSettings::IniFormat);
     QStringList keys = settings.allKeys();

     m_tlpMap.clear();
     for (const QString &key : keys) {
         m_tlpMap.insert("/"+key,  settings.value(key).toString());
     }
     return true;
}

int SysdbusRegister::GetCpuCoreNum()
{
    return m_upmCpuControl->getCpuCoreNum();
}

QString SysdbusRegister::GetCpuCorePolicy(int cpuCoreId)
{
    return m_upmCpuControl->getCpuCorePolicy(cpuCoreId);
}

bool SysdbusRegister::isFlemingXModel()
{
    HardwareReader reader;
    return reader.isFlemingX();
}