/*
 * 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 <QDebug>

#include "powertray.h"
#include "powerwindow.h"

PowerTray::PowerTray(QObject *parent) : QObject(parent)
{
    if (false == UpmUpowerDBus::self()->hasBattery()) {
        qDebug() << "No battery, Program exit";
        exit(0);
    }

    initPowerTray();
    QDBusConnection::systemBus().connect("org.freedesktop.login1",
                                         "/org/freedesktop/login1",
                                         "org.freedesktop.login1.Manager",
                                         "PrepareForSleep",
                                         this,
                                         SLOT(dealWakeUpSignal(bool)));
    m_criticalPercentageAction = new CriticalPercentageAction(this);
}

PowerTray::~PowerTray()
{
    if (nullptr != m_TrayMenu) {
        delete m_TrayMenu;
        m_TrayMenu = nullptr;
    }

    if (nullptr != m_powerWindow) {
        delete m_powerWindow;
        m_powerWindow = nullptr;
    }
}

void PowerTray::initPowerTray()
{
    QVariant value;
    if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_DISPLAY_LEFT_TIME, value)) {
        m_showBatteryLeftTime = value.toInt();
    }
    connect(UpmGsettings::self(), &UpmGsettings::dispalyLeftTimeOfChargeAndDischargeChanged,
            this, [=](QVariant value) {
        m_showBatteryLeftTime = value.toInt();
    });

    m_acChangeTimer = new QTimer(this);
    m_isPowerSupplyChange = false;
    connect(m_acChangeTimer, &QTimer::timeout, this, [=](){
        m_isPowerSupplyChange = false;
        m_acChangeTimer->stop();
    });

    updateBatteryInfo();

    m_trayIcon = new QSystemTrayIcon(this);
    setTrayIconToolTipForAcOnlineChanged(m_acOnlineState, m_batteryPercentage);
    m_trayIconName = UpmUpowerDBus::self()->getBatteryIconName();
    setTrayIcon(m_trayIconName);

    initTrayMenuUI();
    initPowerWindowUI();

    connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(onActivatedIcon(QSystemTrayIcon::ActivationReason)));

    connect(UpmUpowerDBus::self(), &UpmUpowerDBus::acOnlineStateChanged,
            this, &PowerTray::dealAcOnlineStateChanged);
    connect(UpmUpowerDBus::self(), &UpmUpowerDBus::batteryInfoChanged,
            this, &PowerTray::dealBatteryInfoChanged);
}

void PowerTray::initTrayMenuUI()
{
    qDebug() << "init tray menu ui";
    m_TrayMenu = new QMenu();
    m_TrayMenu->setAttribute(Qt::WA_TranslucentBackground);
    m_trayIcon->setContextMenu(m_TrayMenu);
    QAction *setPreference = new QAction(m_TrayMenu);
    QIcon icon = QIcon::fromTheme("document-page-setup-symbolic");
    setPreference->setIcon(icon);
    setPreference->setText(tr("SetPower"));
    connect(setPreference, &QAction::triggered,[=]{QProcess::startDetached(QString("ukui-control-center -m Power"));});
    m_TrayMenu->addAction(setPreference);
}

void PowerTray::initPowerWindowUI()
{
    qDebug() << "init power window ui";
    m_powerWindow = new powerwindow();
    m_powerWindow->hide();

    setPowerWindowProperties();
    m_powerWindow->setPowerStateLabelForAcOnlineChanged();
}

void PowerTray::setPowerWindowProperties()
{
    m_powerWindow->setIconName(m_trayIconName);
    m_powerWindow->setAcOnlineState(m_acOnlineState);
    m_powerWindow->setBatteryState(m_batteryState);
    m_powerWindow->setBatteryPercentage(m_batteryPercentage);
    m_powerWindow->setShowPowerLeftTime(m_showBatteryLeftTime);
    m_powerWindow->setBatteryLeftTime(m_timeToFull, m_timeToEmpty);
}

void PowerTray::setTrayIconToolTipForAcOnlineChanged(bool acOnlineState, double percentage)
{
    if (true == acOnlineState) {
        if (100 == percentage) {
            m_trayIcon->setToolTip(tr("fully charged (100%)"));
        } else {
            m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage));
        }
    } else {
        m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage));
    }
}

void PowerTray::setTrayIconToolTipForBatteryInfoChanged(double percentage)
{
    qint64 batteryLeftTime = 0;
    int hour = 0;

    switch (UpmUpowerDBus::self()->getBatteryState()) {
        case battery_state_unknown:
        case battery_state_fully:
            if (100 == percentage) {
                m_trayIcon->setToolTip(tr("fully charged (100%)"));
            } else {
                m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage));
            }
            break;

        case battery_state_charging:
            batteryLeftTime = m_timeToFull;
            if (0 == m_showBatteryLeftTime || 0 == batteryLeftTime || percentage > 95 ) {
                if (100 == percentage) {
                    m_trayIcon->setToolTip(tr("fully charged (100%)"));
                } else {
                    m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage));
                }
            } else {
                hour = batteryLeftTime / 3600;
                if (0 == hour) {
                    m_trayIcon->setToolTip(tr("%1 min to fully charge (%2%)")
                                           .arg(((batteryLeftTime) % 3600) / 60)
                                           .arg(percentage));
                } else if (hour > 10) {
                    m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage));
                } else {
                    m_trayIcon->setToolTip(tr("%1 hr %2 min to fully charge (%3%)")
                                           .arg(hour)
                                           .arg(((batteryLeftTime) % 3600) / 60)
                                           .arg(percentage));
                }
            }
            break;

        case battery_state_discharging:
            batteryLeftTime = m_timeToEmpty;
            if (0 == m_showBatteryLeftTime || 0 == batteryLeftTime) {
                m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage));
            } else {
                hour = batteryLeftTime / 3600;
                if (0 == hour) {
                    m_trayIcon->setToolTip(tr("%1 min (%2%) remaining")
                                           .arg(((batteryLeftTime) % 3600) / 60)
                                           .arg(percentage));
                } else if (hour > 20) {
                    m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage));
                } else {
                    m_trayIcon->setToolTip(tr("%1 hr %2 min (%3%) remaining")
                                           .arg(hour)
                                           .arg(((batteryLeftTime) % 3600) / 60)
                                           .arg(percentage));
                }
            }
            break;

        default:
            m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage));
            break;
    }
}

void PowerTray::setTrayIcon(QString strIconName)
{
    qDebug() << "icon name is : " << strIconName;
    if (!strIconName.isNull()) {
        QIcon icon = QIcon::fromTheme(strIconName);
        m_trayIcon->setIcon(icon);
        m_trayIcon->show();
    } else {
        m_trayIcon->hide();
    }
}

void PowerTray::onActivatedIcon(QSystemTrayIcon::ActivationReason reason)
{
    if (reason == 3) {
        bool isVisible = m_powerWindow->isVisible();
        qDebug() << "power window is visible:" << isVisible;
        if (true == isVisible) {
            m_powerWindow->hide();
        } else {
            m_powerWindow->showPowerWindow();
        }
    } else {
        qDebug() << "on Activated Icon reason:" << reason;
    }
}

void PowerTray::acOnlineStateChangedAction()
{
    updateBatteryInfo();

    //deal tray icon
    setTrayIconToolTipForAcOnlineChanged(m_acOnlineState, m_batteryPercentage);
    m_trayIconName = UpmUpowerDBus::self()->getBatteryIconName();
    setTrayIcon(m_trayIconName);

    //deal power window
    setPowerWindowProperties();
    m_powerWindow->setPowerStateLabelForAcOnlineChanged();
}

void PowerTray::dealAcOnlineStateChanged(int index, bool value)
{
    qDebug() << "power tray ac online state changed";
    m_isPowerSupplyChange = true;
    m_acChangeTimer->start(120 * 1000);

    acOnlineStateChangedAction();
    if (false == m_acOnlineState) {
        qInfo() << "unplug power";
    }
}

void PowerTray::dealBatteryInfoChanged(int index, QStringList batteryInfoChangedList)
{
    qDebug() << "power tray battery info changed";
    if (true == m_isPowerSupplyChange) {
        qDebug() << "ac online changed, not deal battery info changed";
        acOnlineStateChangedAction();
        return ;
    }

    updateBatteryInfo();
    if (false == m_acOnlineState && m_batteryPercentage < 2) {
        qInfo() << "battery remaining 1%";
    }

    //deal tray icon
    setTrayIconToolTipForBatteryInfoChanged(m_batteryPercentage);

    QString trayIconName = UpmUpowerDBus::self()->getBatteryIconName();
    if (m_trayIconName != trayIconName) {
        m_trayIconName = trayIconName;
        setTrayIcon(m_trayIconName);
    }

    //deal power window
    setPowerWindowProperties();
    m_powerWindow->setPowerStateLabelForBatteryInfoChanged();
}

void PowerTray::dealWakeUpSignal(bool isSleepState)
{
    if (true == isSleepState) {
        qDebug() << "The computer is going to sleep ";
    } else {
        qDebug() << "The computer wakes up ";
        //机器刚从休眠或睡眠中唤醒时，此时不显示时间
        m_isPowerSupplyChange = true;
        m_acChangeTimer->start(60 * 1000);
        acOnlineStateChangedAction();
    }
}

void PowerTray::updateBatteryInfo()
{
    m_acOnlineState = UpmUpowerDBus::self()->getAcOnlineState();
    m_batteryState = UpmUpowerDBus::self()->getBatteryState();
    m_batteryPercentage = UpmUpowerDBus::self()->getBatteryPercentage();
    m_timeToFull = UpmUpowerDBus::self()->getTimeToFull();
    m_timeToEmpty = UpmUpowerDBus::self()->getTimeToEmpty();
}

