/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
 * -*- coding: utf-8 -*-
 *
 * Copyright (C) 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
 * 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 "gamma-manager-wayland.h"
#include "gamma-color-info.h"

GammaManagerWayland *GammaManagerWayland::m_gammaWaylandManager = nullptr;

//struct ColorInfoWayland {
//    QString arg;
//    QDBusVariant out;
//};

//QDBusArgument &operator<<(QDBusArgument &argument, const ColorInfoWayland &mystruct)
//{
//    argument.beginStructure();
//    argument << mystruct.arg << mystruct.out;
//    argument.endStructure();
//    return argument;
//}

//const QDBusArgument &operator>>(const QDBusArgument &argument, ColorInfoWayland &mystruct)
//{
//    argument.beginStructure();
//    argument >> mystruct.arg >> mystruct.out;
//    argument.endStructure();
//    return argument;
//}

//Q_DECLARE_METATYPE(ColorInfoWayland)

/*
 * TODO:kwin使用的时天黑时间，而非日落时间。日落时间一般比天黑时间早半小时，需要提取kwin的算法。
*/
GammaManagerWayland::GammaManagerWayland()
{
    m_pColorSettings = new QGSettings(USD_COLOR_SCHEMA);
    m_pQtSettings    = new QGSettings(QT_THEME_SCHEMA);
    m_pGtkSettings   = new QGSettings(GTK_THEME_SCHEMA);
    m_pukuiGtkConfig = new UkuiGtkConfig(this);
    m_pGmLocation    = new GmLocation(this);

    m_darkModeChangedBySelf = false;
    m_pclockSkewNotifier = new USD::ClockSkewNotifier(this);

    m_pTimer = new QTimer(this);
    m_pTimer->setSingleShot(false);
    m_pTimer->start(60000);

    checkEyeCareMode(EYE_CARE_MOEDE);
    connect(m_pclockSkewNotifier, SIGNAL(clockSkewed(QString)), SLOT(doColorSettingsChanged(QString)));
    connect(m_pQtSettings, SIGNAL(changed(QString)), this, SLOT(doQtSettingsChanged(QString)));
    connect(m_pColorSettings, SIGNAL(changed(QString)), this, SLOT(doColorSettingsChanged(QString)), Qt::AutoConnection);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(doCheckTimeout()), Qt::DirectConnection);

     m_inDark = m_pColorSettings->get(COLOR_KEY_AUTO_THEME).toBool();
}

GammaManagerWayland::~GammaManagerWayland()
{
     USD_LOG(LOG_DEBUG,"wayland.....");
}

GammaManagerWayland *GammaManagerWayland::GammaManagerWaylandNew()
{
    if (m_gammaWaylandManager == nullptr) {
        m_gammaWaylandManager = new GammaManagerWayland();
    }
    return m_gammaWaylandManager;
}

bool GammaManagerWayland::Start()
{

    USD_LOG(LOG_DEBUG,"wayland start.....");
    m_pGmLocation->setGsettings(m_pColorSettings);
    m_pGmLocation->start();
    syncColorSetToKwin();
    m_pukuiGtkConfig->connectGsettingSignal();
    return true;
}

void GammaManagerWayland::Stop()
{
    USD_LOG(LOG_DEBUG,"wayland Stop.....");
    if (m_pColorSettings) {
        delete m_pColorSettings;
        m_pColorSettings = nullptr;
    }

    if (m_pQtSettings) {
        delete m_pQtSettings;
        m_pQtSettings = nullptr;
    }

    if (m_pGtkSettings) {
        delete m_pGtkSettings;
        m_pGtkSettings = nullptr;
    }

    if (m_pukuiGtkConfig) {
        delete m_pukuiGtkConfig;
        m_pukuiGtkConfig = nullptr;
    }

    if (m_pGmLocation) {
        delete m_pGmLocation;
        m_pGmLocation = nullptr;
    }

}

void GammaManagerWayland::doQtSettingsChanged(QString setKey)
{
    if (setKey == QT_THEME_KEY) {
        bool isAllDay = m_pColorSettings->get(COLOR_KEY_ALLDAY).toBool();
        bool isEnable = m_pColorSettings->get(COLOR_KEY_ENABLED).toBool();
        USD_LOG(LOG_DEBUG,"get key:",setKey.toLatin1().data());
        if (m_pQtSettings->get(setKey).toString() != "ukui-dark") {
            if (m_pColorSettings->get(COLOR_KEY_DARK_MODE).toBool()) {
                m_darkModeChangedBySelf = true;
                m_pColorSettings->set(COLOR_KEY_STYLE_NAME_DM, m_pQtSettings->get(QT_THEME_KEY).toString());
                m_pColorSettings->set(COLOR_KEY_DARK_MODE,false);
                m_pColorSettings->apply();
            }
        }

        QString theme = m_pQtSettings->get(QT_THEME_KEY).toString();
        if (isAllDay && isEnable && theme == "ukui-dark") {
            m_darkModeChangedBySelf = true;
            m_pColorSettings->set(COLOR_KEY_DARK_MODE, true);
            m_pColorSettings->apply();
        }
    }
}


void GammaManagerWayland::doColorSettingsChanged(QString setKey)
{
    USD_LOG(LOG_DEBUG,"change key:%s.",setKey.toLatin1().data());

    checkEyeCareMode(setKey);
    if (isDarkMode(setKey)) {
        USD_LOG(LOG_DEBUG,"get dark mode..");
        return;
    }
    syncColorSetToKwin();
    checkAutoTheme();
}

void GammaManagerWayland::doCheckTimeout()
{
    syncColorSetToKwin();
    checkAutoTheme();
}

void GammaManagerWayland::syncColorSetToKwin()
{
    QHash<QString, QVariant> nightConfig;
    QVector<ColorInfo> nightColor;

    QDBusInterface colorIft("org.ukui.KWin",
                            "/ColorCorrect",
                            "org.ukui.kwin.ColorCorrect",
                            QDBusConnection::sessionBus());

    QDBusMessage result = colorIft.call("nightColorInfo");

    if (result.type() != QDBusMessage::ReplyMessage) {
        USD_LOG(LOG_ERR,"call error...ready call syncColorSetToKwinOpenkylin()");
        syncColorSetToKwinWithSetSingleProp();
        return;
    }
    const QDBusArgument &dbusArgs = result.arguments().at(0).value<QDBusArgument>().asVariant().value<QDBusArgument>();

    dbusArgs.beginArray();
    while (!dbusArgs.atEnd()) {
        ColorInfo color;
        dbusArgs >> color;
        nightColor.push_back(color);
    }
    dbusArgs.endArray();

    for (ColorInfo it : nightColor) {
        nightConfig.insert(it.arg, it.out.variant());
    }

    if (m_pColorSettings->get(EYE_CARE_MOEDE).toBool()) {
        syncEyeCareToDbus(colorIft, nightConfig);
    } else {
        syncColorToDbus(colorIft, nightConfig);
    }
}

void GammaManagerWayland::syncColorToDbus(QDBusInterface &colorIft, QHash<QString, QVariant> nightConfig)
{
    if (m_pColorSettings->get(COLOR_KEY_ENABLED).toBool()) {
        nightConfig[KWIN_COLOR_ACTIVE] = true;
    } else {
        nightConfig[KWIN_COLOR_ACTIVE] = false;
    }

    if (m_pColorSettings->get(COLOR_KEY_ALLDAY).toBool()) {
        nightConfig[KWIN_COLOR_MODE] = (uint)3;
    } else if (m_pColorSettings->get(COLOR_KEY_AUTOMATIC).toBool()) {
        QVariant qVar = m_pColorSettings->get(COLOR_KEY_LAST_COORDINATES);
        QVariantList qVarList =  qVar.value<QVariantList>();

        if(qVarList[1].toDouble() > -180 && qVarList[1].toDouble() < 180 &&
                qVarList[0].toDouble() > -90 && qVarList[0].toDouble() < 90) {
            nightConfig[KWIN_COLOR_MODE] = (uint)1;
            nightConfig[KWIN_LATITUDE] = qVarList[0].toDouble();
            nightConfig[KWIN_LONGITUDE] = qVarList[1].toDouble();
        } else {//未设置网络走自定义时长
            nightConfig[KWIN_COLOR_MODE] = (uint)2;//自定义时长
            int hour = floor(m_pColorSettings->get(COLOR_KEY_FROM).toDouble());
            int min = (m_pColorSettings->get(COLOR_KEY_FROM).toDouble() - hour)*60;
            nightConfig[KWIN_COLOR_START] = QString("%1:%2:00").arg(hour,2,10,QLatin1Char('0')).arg(min,2,10,QLatin1Char('0'));
            hour = floor(m_pColorSettings->get(COLOR_KEY_TO).toDouble());
            min = (m_pColorSettings->get(COLOR_KEY_TO).toDouble() - hour)*60;
        }

    } else {
        nightConfig[KWIN_COLOR_MODE] = (uint)2;//自定义时长
        int hour = floor(m_pColorSettings->get(COLOR_KEY_FROM).toDouble());
        int min = (m_pColorSettings->get(COLOR_KEY_FROM).toDouble() - hour)*60;
        nightConfig[KWIN_COLOR_START] = QString("%1:%2:00").arg(hour,2,10,QLatin1Char('0')).arg(min,2,10,QLatin1Char('0'));
        hour = floor(m_pColorSettings->get(COLOR_KEY_TO).toDouble());
        min = (m_pColorSettings->get(COLOR_KEY_TO).toDouble() - hour)*60;
        nightConfig[KWIN_COLOR_END] = QString("%1:%2:00").arg(hour,2,10,QLatin1Char('0')).arg(min,2,10,QLatin1Char('0'));
    }


    nightConfig[KWIN_NIGHT_TEMP] = m_pColorSettings->get(COLOR_KEY_TEMPERATURE).toInt();

    colorIft.call("setNightColorConfig", nightConfig);
    USD_LOG(LOG_DEBUG,"ready send to kwin..");
    USD_LOG(LOG_DEBUG, "active:%d,mode:%d,temp:%d long:%f lat:%f",nightConfig[KWIN_COLOR_ACTIVE].toBool(), nightConfig[KWIN_COLOR_MODE].toInt(),
            nightConfig[KWIN_NIGHT_TEMP].toInt(),nightConfig[KWIN_LONGITUDE].toDouble(),nightConfig[KWIN_LATITUDE].toDouble());


}

void GammaManagerWayland::syncEyeCareToDbus(QDBusInterface &colorIft, QHash<QString, QVariant> nightConfig)
{
    int temperature,interpolateStart;
    double scheduleFrom,scheduleTo;
    nightConfig[KWIN_COLOR_ACTIVE] = true;

    getEyeCareDate(temperature, interpolateStart, scheduleFrom, scheduleTo);
    USD_LOG_SHOW_PARAM2F(scheduleFrom, scheduleTo);
    USD_LOG_SHOW_PARAM1(temperature);
    USD_LOG_SHOW_PARAM1(interpolateStart);
    temperature = getSetTempInEyeCare(temperature, interpolateStart, scheduleFrom, scheduleTo);

    //for three level
    nightConfig[KWIN_COLOR_MODE] = (uint)3;
    nightConfig[KWIN_NIGHT_TEMP] = temperature;
    colorIft.call("setNightColorConfig", nightConfig);
    USD_LOG(LOG_DEBUG, "active:%d,mode:%d,temp:%d long:%f lat:%f",nightConfig[KWIN_COLOR_ACTIVE].toBool(), nightConfig[KWIN_COLOR_MODE].toInt(),
            nightConfig[KWIN_NIGHT_TEMP].toInt(),nightConfig[KWIN_LONGITUDE].toDouble(),nightConfig[KWIN_LATITUDE].toDouble());

}


void GammaManagerWayland::getEyeCareDate(int& temperature, int& interpolateStart, double& scheduleFrom, double& scheduleTo)
{
    double autoScheduleFrom,autoScheduleTo,fracDay;

    QTime rtTime = QTime::currentTime();
    fracDay = getFracTimeFromDt(rtTime);

    autoScheduleFrom = m_pColorSettings->get(COLOR_KEY_AUTOMATIC_FROM).toDouble();
    autoScheduleTo = m_pColorSettings->get(COLOR_KEY_AUTOMATIC_TO).toDouble();

    QVariant qVar = m_pColorSettings->get(COLOR_KEY_LAST_COORDINATES);
    QVariantList qVarList =  qVar.value<QVariantList>();

    if(!(qVarList[1].toDouble() > -180 && qVarList[1].toDouble() < 180 &&
            qVarList[0].toDouble() > -90 && qVarList[0].toDouble() < 90)) {
        autoScheduleFrom = m_pColorSettings->get(COLOR_KEY_FROM).toDouble();
        autoScheduleTo = m_pColorSettings->get(COLOR_KEY_TO).toDouble();
        USD_LOG(LOG_DEBUG,"latitude and longitude error use user config");
    }

    /* smear the temperature for a short duration before the set limits
    *
    *  ---|                                         |------ = to->from(EYE_CARE_VALUE_DAY)
    *     |-|                                     |-| = smear down
    *       |---|                             |---| = from->1, 3->to  evening and dawn (EYE_CARE_VALUE_EVENING_DAWN)
    *           |-|                         |-| = smear down
    *             |-------------------------| =  late at night  (EYE_CARE_VALUE_LATE_NIGHT)
    */

    // evening
    if (isFracDayBetween (fracDay,
                           autoScheduleFrom,
                          DEEP_NIGHT_START)) {
        temperature = m_pColorSettings->get(EYE_CARE_VALUE_EVENING_DAWN).toInt();
        scheduleFrom = autoScheduleFrom;
        scheduleTo = DEEP_NIGHT_START;
        interpolateStart = m_pColorSettings->get(EYE_CARE_VALUE_LATE_NIGHT).toInt();
        USD_LOG(LOG_DEBUG,"in evening");
        return;
    }

    //dawn
    if (isFracDayBetween (fracDay,
                          DEEP_NIGHT_END,
                          autoScheduleTo)) {
        temperature =  m_pColorSettings->get(EYE_CARE_VALUE_EVENING_DAWN).toInt();
        scheduleFrom = DEEP_NIGHT_END;
        scheduleTo = autoScheduleTo;
        interpolateStart = m_pColorSettings->get(EYE_CARE_VALUE_DAY).toInt();
        USD_LOG(LOG_DEBUG,"in dawn1");
        return;
    }

    // late at night
    if (isFracDayBetween (fracDay,
                          DEEP_NIGHT_START,
                          DEEP_NIGHT_END)) {
        temperature =  m_pColorSettings->get(EYE_CARE_VALUE_LATE_NIGHT).toInt();
        scheduleFrom = DEEP_NIGHT_START;
        scheduleTo = DEEP_NIGHT_END;
        interpolateStart = m_pColorSettings->get(EYE_CARE_VALUE_EVENING_DAWN).toInt();
        USD_LOG(LOG_DEBUG,"in late at night");
        return;
    }

    // all night
    if (isFracDayBetween (fracDay,
                           autoScheduleTo,
                           autoScheduleFrom)) {
        temperature =  m_pColorSettings->get(EYE_CARE_VALUE_DAY).toInt();
        scheduleFrom = autoScheduleTo;
        scheduleTo = autoScheduleFrom;
        interpolateStart = m_pColorSettings->get(EYE_CARE_VALUE_EVENING_DAWN).toInt();
        USD_LOG(LOG_DEBUG,"in day");
        return;
    }
}

int GammaManagerWayland::getSetTempInEyeCare(int temperature, int interpolateStart, double scheduleFrom, double scheduleTo)
{
    double fracDay;
    double smear = USD_NIGHT_LIGHT_POLL_SMEAR; /* hours */
    uint tempSmeared;
    QTime rtTime = QTime::currentTime();

    fracDay = getFracTimeFromDt(rtTime);

    /* lower smearing period to be smaller than the time between start/stop */
    smear = qMin (smear,
                (qMin (qAbs ((scheduleTo - scheduleFrom)),
                     (24 - qAbs ((scheduleTo - scheduleFrom))))));

    USD_LOG(LOG_DEBUG,"fracDay:%.2f, %.2f %.2f", fracDay,scheduleFrom - smear, scheduleTo);
    if (!isFracDayBetween (fracDay,
                           scheduleFrom - smear,
                           scheduleTo)) {
        USD_LOG(LOG_DEBUG,"in smeared...");
        return interpolateStart;
    }

    /* smear the temperature for a short duration before the set limits
    *
    *   |----------------------| = from->to
    * |-|                        = smear down
    *                        |-| = smear up
    *
    * \                        /
    *  \                      /
    *   \--------------------/
    */

    if (smear < 0.01) {
        /* Don't try to smear for extremely short or zero periods */
        tempSmeared = temperature;
        USD_LOG(LOG_DEBUG,"can't smeared...");
    } else if (isFracDayBetween(fracDay,
                                           scheduleFrom - smear,
                                           scheduleFrom)) {
        double factor = 1.f - ((fracDay - (scheduleFrom - smear)) / smear);
        tempSmeared = linearInterpolate (interpolateStart,
                                          temperature, factor);
        USD_LOG(LOG_DEBUG,"interpolateStart:%d temperature:%d factor:%f,frac_day:%f,schedule_from:%f",interpolateStart, temperature, factor,
                fracDay,scheduleFrom);
    } else if (isFracDayBetween (fracDay,
                                           scheduleTo - smear,
                                           scheduleTo)) {
        double factor = (fracDay - (scheduleTo - smear)) / smear;
        tempSmeared = linearInterpolate (interpolateStart,
                                          temperature, factor);
        USD_LOG(LOG_DEBUG,"interpolateStart:%d temperature:%d factor:%f,frac_day:%f,schedule_from:%f",interpolateStart, temperature, factor,
                fracDay,scheduleTo);
    } else {
        tempSmeared = temperature;
    }
    USD_LOG_SHOW_PARAM2(tempSmeared, (interpolateStart-tempSmeared));

    return tempSmeared;
}

bool GammaManagerWayland::isFracDayBetween(double value, double start, double end)
{
    if (end <= start) {
        end += 24;
    }

    if (value < start && value < end) {
        value += 24;
    }

   return value >= start && value < end;
}

void GammaManagerWayland::syncColorSetToKwinWithSetSingleProp()
{
    // Register custom types for DBus communication
    qDBusRegisterMetaType<QByteArrayList>();
    qDBusRegisterMetaType<QHash<QString, QByteArrayList>>();

    // Define the properties that have changed
    QStringList changeProps;
    changeProps.append("NightColor.Mode");

    // Get the path to kwinrc config file
    const QString kwinrcPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/kwinrc");

    // Open the kwinrc config file
    QSettings kwinrcConfig(kwinrcPath, QSettings::IniFormat);

    if (m_pColorSettings->get(EYE_CARE_MOEDE).toBool()) {
        syncEyeCareToKwinrc(kwinrcConfig);
    } else {
        syncColorToKwinrc(kwinrcConfig);
    }

    // End the NightColor group and sync the changes to the config file
    kwinrcConfig.endGroup();
    kwinrcConfig.sync();

    // Emit a signal indicating the changed properties
    sendConfigChangedSignal(changeProps);
}

void GammaManagerWayland::syncColorToKwinrc(QSettings &kwinrcConfig)
{
    // Begin the group for NightColor
    kwinrcConfig.beginGroup("NightColor");

    // Set the Active property based on the enabled state
    kwinrcConfig.setValue("Active", m_pColorSettings->get(COLOR_KEY_ENABLED).toBool());

    // Set the Mode property based on the all-day or automatic state
    if (m_pColorSettings->get(COLOR_KEY_ALLDAY).toBool()) {
        kwinrcConfig.setValue("Mode", "Constant");
    } else if (m_pColorSettings->get(COLOR_KEY_AUTOMATIC).toBool()) {
        kwinrcConfig.remove("Mode");
        QVariantList qVarList = m_pColorSettings->get(COLOR_KEY_LAST_COORDINATES).value<QVariantList>();
        kwinrcConfig.setValue("LatitudeAuto", qVarList[0]);
        kwinrcConfig.setValue("LongitudeAuto", qVarList[1]);
    } else {
        const double startTime = m_pColorSettings->get(COLOR_KEY_FROM).toDouble();
        const double endTime = m_pColorSettings->get(COLOR_KEY_TO).toDouble();
        const int start = ((int)startTime) * 100 + (startTime - ((int)startTime)) * 60.0;
        const int end = ((int)endTime) * 100 + (endTime - ((int)endTime)) * 60.0;
        kwinrcConfig.setValue("EveningBeginFixed", start);
        kwinrcConfig.setValue("MorningBeginFixed", end);
    }

    // Set the NightTemperature property
    kwinrcConfig.setValue("NightTemperature", m_pColorSettings->get(COLOR_KEY_TEMPERATURE).toInt());
}

void GammaManagerWayland::syncEyeCareToKwinrc(QSettings &kwinrcConfig)
{
    int temperature,interpolateStart;
    double scheduleFrom,scheduleTo;

    getEyeCareDate(temperature, interpolateStart, scheduleFrom, scheduleTo);
    temperature = getSetTempInEyeCare(temperature, interpolateStart, scheduleFrom, scheduleTo);
    // Begin the group for NightColor
    kwinrcConfig.beginGroup("NightColor");

    // Set the Active property based on the enabled state
    kwinrcConfig.setValue("Active", m_pColorSettings->get(EYE_CARE_MOEDE).toBool());

    kwinrcConfig.setValue("Mode", "Constant");
    kwinrcConfig.setValue("NightTemperature", temperature);
    USD_LOG(LOG_DEBUG,"temp:%d",temperature);
}


void GammaManagerWayland::checkEyeCareMode(QString key)
{
    bool isColorEnable = m_pColorSettings->get(COLOR_KEY_ENABLED).toBool();
    bool isEyeCareEnable = m_pColorSettings->get(EYE_CARE_MOEDE).toBool();
    USD_LOG_SHOW_PARAM1(isEyeCareEnable);
    USD_LOG_SHOW_PARAM1(isColorEnable);

    if (key == COLOR_KEY_ENABLED && isColorEnable) {
        m_pColorSettings->set(EYE_CARE_MOEDE,false);
        USD_LOG(LOG_DEBUG,"close eye_care");
    } else if (key ==EYE_CARE_MOEDE && isEyeCareEnable) {
        m_pColorSettings->set(COLOR_KEY_ENABLED,false);
        USD_LOG(LOG_DEBUG,"close color");
    }

    m_pColorSettings->apply();

}

bool GammaManagerWayland::isDarkMode(QString key)
{
    bool darkMode = m_pColorSettings->get(COLOR_KEY_DARK_MODE).toBool();
    bool ret;
    if (key.contains("-dm") || key == COLOR_KEY_REAL_TIME_TEMPERATURE) {
        return true;
    }

    //外部修改，则直接退出夜间模式。
    if (key == COLOR_KEY_ALLDAY || key == COLOR_KEY_ENABLED) {
        bool isAllDay = m_pColorSettings->get(COLOR_KEY_ALLDAY).toBool();
        bool isEnable = m_pColorSettings->get(COLOR_KEY_ENABLED).toBool();

        if (darkMode && false == (isAllDay & isEnable)) {
            m_darkModeChangedBySelf = true;
            m_pColorSettings->set(COLOR_KEY_DARK_MODE,false);
            m_pColorSettings->apply();
            return false;
        } else  if (isAllDay && isEnable && (darkMode == false)){
            if (m_pQtSettings->get(QT_THEME_KEY).toString() == "ukui-dark") {
                m_darkModeChangedBySelf = true;
                m_pColorSettings->set(COLOR_KEY_DARK_MODE,true);
                m_pColorSettings->apply();
                USD_LOG(LOG_DEBUG,"enter dark mode..");
                return false;
            }
        }
    } else if (key == COLOR_KEY_AUTOMATIC) {
        ret = m_pColorSettings->get(key).toBool();
        if (darkMode && true == ret) {
            m_darkModeChangedBySelf = true;
            m_pColorSettings->set(COLOR_KEY_DARK_MODE,false);
            m_pColorSettings->apply();
            return false;
        }
    } else if (key == COLOR_KEY_AUTO_THEME) {
        ret = m_pColorSettings->get(key).toBool();
        if (darkMode && true == ret) {
            m_darkModeChangedBySelf = true;
            m_pColorSettings->set(COLOR_KEY_DARK_MODE,false);
            m_pColorSettings->apply();
            return false;
        }
    }

    if (key == COLOR_KEY_DARK_MODE) {
        if (m_darkModeChangedBySelf) {
            USD_LOG(LOG_DEBUG, "skip it....");
            m_darkModeChangedBySelf = false;
            return true;
        }
        int inDark = m_pColorSettings->get(key).toBool();
        if (m_inDark == inDark) {
            return true;
        }
        if (inDark) {//进入夜间模式
            m_pColorSettings->delay();
            m_pColorSettings->set(COLOR_KEY_ALLDAY_DM, m_pColorSettings->get(COLOR_KEY_ALLDAY).toBool());
            m_pColorSettings->set(COLOR_KEY_ENABLED_DM, m_pColorSettings->get(COLOR_KEY_ENABLED).toBool());
            m_pColorSettings->set(COLOR_KEY_AUTOMATIC_DM, m_pColorSettings->get(COLOR_KEY_AUTOMATIC).toBool());
            m_pColorSettings->set(COLOR_KEY_STYLE_NAME_DM, m_pQtSettings->get(QT_THEME_KEY).toString());
            m_pColorSettings->set(COLOR_KEY_AUTO_THEME_DM, m_pColorSettings->get(COLOR_KEY_AUTO_THEME).toString());//四个任意一个改变则退出夜间模式。

            m_pColorSettings->set(COLOR_KEY_ALLDAY, true);
            m_pColorSettings->set(COLOR_KEY_ENABLED, true);
            m_pColorSettings->set(COLOR_KEY_AUTOMATIC, false);

            m_pColorSettings->set(COLOR_KEY_AUTO_THEME, false);
            m_pQtSettings->set(QT_THEME_KEY, "ukui-dark");
            m_pGtkSettings->set(GTK_THEME_KEY, "ukui-black");
            m_pColorSettings->apply();
            syncColorSetToKwin();
            USD_LOG(LOG_DEBUG, "enter dark mode");
        } else {//退出夜间模式1
            m_pColorSettings->delay();
            m_pColorSettings->set(COLOR_KEY_ALLDAY, m_pColorSettings->get(COLOR_KEY_ALLDAY_DM).toBool());
            m_pColorSettings->set(COLOR_KEY_ENABLED, m_pColorSettings->get(COLOR_KEY_ENABLED_DM).toBool());
            m_pColorSettings->set(COLOR_KEY_AUTOMATIC, m_pColorSettings->get(COLOR_KEY_AUTOMATIC_DM).toBool());
            m_pColorSettings->set(COLOR_KEY_AUTO_THEME, m_pColorSettings->get(COLOR_KEY_AUTO_THEME_DM).toBool());

            if (false == m_pColorSettings->get(COLOR_KEY_AUTO_THEME).toBool()) {
                if (m_pColorSettings->get(COLOR_KEY_STYLE_NAME_DM).toString() == "ukui-default") {
                    m_pQtSettings->set(QT_THEME_KEY, "ukui-default");
                    m_pGtkSettings->set(GTK_THEME_KEY, "ukui-white");
                } else if(m_pColorSettings->get(COLOR_KEY_STYLE_NAME_DM).toString() == "ukui-light"){
                    m_pQtSettings->set(QT_THEME_KEY, "ukui-light");
                    m_pGtkSettings->set(GTK_THEME_KEY, "ukui-white");
                } else {
                    m_pQtSettings->set(QT_THEME_KEY, "ukui-dark");
                    m_pGtkSettings->set(GTK_THEME_KEY, "ukui-black");
                }
            }
            m_pColorSettings->apply();
            syncColorSetToKwin();
            USD_LOG(LOG_DEBUG, "exit dark mode");
        }
        m_inDark = inDark;
        return true;
    }

    return false;
}

void GammaManagerWayland::sendConfigChangedSignal(QStringList list)
{
    QDBusMessage notifySignal =
            QDBusMessage::createSignal("/kwinrc", "org.kde.kconfig.notify", "ConfigChanged");

    QHash<QString, QByteArrayList> signalArgs;
    QByteArrayList signalArray;

    Q_FOREACH (const QString &msg, list) {
        signalArray.append(msg.toUtf8());
    }

    signalArgs.insert("NightColor",signalArray);
    notifySignal.setArguments({QVariant::fromValue(signalArgs)});
    QDBusConnection::sessionBus().send(notifySignal);

    QTimer::singleShot(5*1000, this, [this](){
        disableNightColorWithOutSignal();
        USD_LOG(LOG_DEBUG,"signalShot to disable for next login with X........");
    });
}

void GammaManagerWayland::disableNightColorWithOutSignal()
{
    // Register custom types for DBus communication
    qDBusRegisterMetaType<QByteArrayList>();
    qDBusRegisterMetaType<QHash<QString, QByteArrayList>>();

    // Define the properties that have changed
    QStringList changeProps;
    changeProps.append("NightColor.Mode");

    // Get the path to kwinrc config file
    const QString kwinrcPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/kwinrc");

    // Open the kwinrc config file
    QSettings kwinrcConfig(kwinrcPath, QSettings::IniFormat);

    // Begin the group for NightColor
    kwinrcConfig.beginGroup("NightColor");

    // Remove the Active property
    kwinrcConfig.remove("Active");

    // End the NightColor group and sync the changes to the config file
    kwinrcConfig.endGroup();
    kwinrcConfig.sync();
}

void GammaManagerWayland::checkAutoTheme()
{
    double fracDay;
    double scheduleFrom = -1.f;
    double scheduleTo = -1.f;

    QTime rtTime = QTime::currentTime();

    fracDay = getFracTimeFromDt(rtTime);
    //跟随日出日落
    if (m_pColorSettings->get(COLOR_KEY_AUTOMATIC).toBool()) {
        scheduleFrom = m_pColorSettings->get(COLOR_KEY_AUTOMATIC_FROM).toDouble();
        scheduleTo = m_pColorSettings->get(COLOR_KEY_AUTOMATIC_TO).toDouble();
        if (scheduleFrom < 0.f || scheduleTo < 0.f) {
            scheduleFrom = m_pColorSettings->get(COLOR_KEY_FROM).toDouble();
            scheduleTo = m_pColorSettings->get(COLOR_KEY_TO).toDouble();
        }
    } else {
        scheduleFrom = m_pColorSettings->get(COLOR_KEY_FROM).toDouble();
        scheduleTo = m_pColorSettings->get(COLOR_KEY_TO).toDouble();
    }

    //自动主题
    if (m_pColorSettings->get(COLOR_KEY_AUTO_THEME).toBool()) {
        USD_LOG_SHOW_PARAM2F(scheduleFrom, scheduleTo);
        USD_LOG_SHOW_PARAMF(fracDay);
        if (isFracDayBetween(fracDay, scheduleFrom, scheduleTo)) {
            m_pGtkSettings->set(GTK_THEME_KEY, "ukui-black");
            m_pQtSettings->set(QT_THEME_KEY, "ukui-dark");
        } else {
            m_pGtkSettings->set(GTK_THEME_KEY, "ukui-white");
            m_pQtSettings->set(QT_THEME_KEY, "ukui-light");
        }
    }
}

double GammaManagerWayland::linearInterpolate(double val1, double val2, double factor)
{
    USD_CHECK_RETURN (factor >= 0.f, -1.f);
    USD_CHECK_RETURN (factor <= 1.f, -1.f);
    return ((val1 - val2) * factor) + val2;
}

double GammaManagerWayland::getFracTimeFromDt(QTime dt)
{
    return dt.hour() + (double) dt.minute() / 60 + (double) dt.second() / 3600;
}

