/*
* Copyright (c) 2014, 2015 Christian Surlykke, Paulo Lieuthier
*
* This file is part of the LXQt project. <https://lxqt.org>
* It is distributed under the LGPL 2.1 or later license.
* Please refer to the LICENSE file for a copy of the license.
*/
#include "iconproducer.h"
#include <LXQt/Settings>
#include <XdgIcon>
#include <QDebug>
#include <QtSvg/QSvgRenderer>
#include <QPainter>
#include <math.h>

IconProducer::IconProducer(Solid::Battery *battery, QObject *parent) : QObject(parent)
{
    connect(battery, &Solid::Battery::chargeStateChanged, this, &IconProducer::updateState);
    connect(battery, &Solid::Battery::chargePercentChanged, this, &IconProducer::updateChargePercent);
    connect(&mSettings, SIGNAL(settingsChanged()), this, SLOT(update()));

    mChargePercent = battery->chargePercent();
    mState = battery->chargeState();
    themeChanged();
}

IconProducer::IconProducer(QObject *parent):  QObject(parent)
{
    themeChanged();
    update();
}


void IconProducer::updateChargePercent(int newChargePercent)
{
    mChargePercent = newChargePercent;

    update();
}

void IconProducer::updateState(int newState)
{
    mState = (Solid::Battery::ChargeState) newState;

    update();
}

void IconProducer::update()
{
    QString newIconName;

    if (mSettings.isUseThemeIcons())
    {
        QMap<float, QString> *levelNameMap = (mState == Solid::Battery::Discharging ? &mLevelNameMapDischarging : &mLevelNameMapCharging);
        const auto levels = levelNameMap->keys();
        for (const float level : levels)
        {
            if (level >= mChargePercent)
            {
                newIconName = levelNameMap->value(level);
                break;
            }
        }
    }

    if (mSettings.isUseThemeIcons() && newIconName == mIconName)
        return;

    mIconName = newIconName;
    mIcon = mSettings.isUseThemeIcons() ? QIcon::fromTheme(mIconName) : circleIcon();
    emit iconChanged();
}

void IconProducer::themeChanged()
{
    /*
     * We maintain specific charge-level-to-icon-name mappings for Oxygen and Awoken and
     * asume all other themes adhere to the freedesktop standard.
     * This is certainly not true, and as bug reports come in stating that
     * this and that theme is not working we will probably have to add new
     * mappings beside Oxygen and Awoken
     */
    mLevelNameMapDischarging.clear();
    mLevelNameMapCharging.clear();

    if (QIcon::themeName() == "oxygen")
    {
        // Means:
        // Use 'battery-low' for levels up to 10
        //  -  'battery-caution' for levels between 10 and 20
        //  -  'battery-040' for levels between 20 and 40, etc..
        mLevelNameMapDischarging[10] = "battery-low";
        mLevelNameMapDischarging[20] = "battery-caution";
        mLevelNameMapDischarging[40] = "battery-040";
        mLevelNameMapDischarging[60] = "battery-060";
        mLevelNameMapDischarging[80] = "battery-080";
        mLevelNameMapDischarging[101] = "battery-100";
        mLevelNameMapCharging[10] = "battery-charging-low";
        mLevelNameMapCharging[20] = "battery-charging-caution";
        mLevelNameMapCharging[40] = "battery-charging-040";
        mLevelNameMapCharging[60] = "battery-charging-060";
        mLevelNameMapCharging[80] = "battery-charging-080";
        mLevelNameMapCharging[101] = "battery-charging";
    }
    else if (QIcon::themeName().startsWith("AwOken")) // AwOken, AwOkenWhite, AwOkenDark
    {
        mLevelNameMapDischarging[5] = "battery-000";
        mLevelNameMapDischarging[30] = "battery-020";
        mLevelNameMapDischarging[50] = "battery-040";
        mLevelNameMapDischarging[70] = "battery-060";
        mLevelNameMapDischarging[95] = "battery-080";
        mLevelNameMapDischarging[101] = "battery-100";
        mLevelNameMapCharging[5] = "battery-000-charging";
        mLevelNameMapCharging[30] = "battery-020-charging";
        mLevelNameMapCharging[50] = "battery-040-charging";
        mLevelNameMapCharging[70] = "battery-060-charging";
        mLevelNameMapCharging[95] = "battery-080-charging";
        mLevelNameMapCharging[101] = "battery-100-charging";
    }
    else // As default we fall back to the freedesktop scheme.
    {
        mLevelNameMapDischarging[3] = "battery-empty";
        mLevelNameMapDischarging[10] = "battery-caution";
        mLevelNameMapDischarging[50] = "battery-low";
        mLevelNameMapDischarging[90] = "battery-good";
        mLevelNameMapDischarging[101] = "battery-full";
        mLevelNameMapCharging[3] = "battery-empty";
        mLevelNameMapCharging[10] = "battery-caution-charging";
        mLevelNameMapCharging[50] = "battery-low-charging";
        mLevelNameMapCharging[90] = "battery-good-charging";
        mLevelNameMapCharging[101] = "battery-full-charging";
    }

    update();
}

QIcon& IconProducer::circleIcon()
{
    static QMap<Solid::Battery::ChargeState, QMap<int, QIcon> > cache;

    int chargeLevelAsInt = (int) (mChargePercent + 0.49);

    if (!cache[mState].contains(chargeLevelAsInt))
        cache[mState][chargeLevelAsInt] = buildCircleIcon(mState, mChargePercent);

    return cache[mState][chargeLevelAsInt];
}

QIcon IconProducer::buildCircleIcon(Solid::Battery::ChargeState state, int chargeLevel)
{
    static QString svg_template =
        "<svg\n"
        "    xmlns:dc='http://purl.org/dc/elements/1.1/'\n"
        "    xmlns:cc='http://creativecommons.org/ns#'\n"
        "    xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n"
        "    xmlns:svg='http://www.w3.org/2000/svg'\n"
        "    xmlns='http://www.w3.org/2000/svg'\n"
        "    version='1.1'\n"
        "    width='200'\n"
        "    height='200'>\n"
        "\n"
        "<defs>\n"
        "    <linearGradient id='greenGradient' x1='0%' y1='0%' x2='100%' y2='100%'>\n"
        "        <stop offset='0%' style='stop-color:rgb(125,255,125);stop-opacity:1' />\n"
        "        <stop offset='150%' style='stop-color:rgb(15,125,15);stop-opacity:1' />\n"
        "    </linearGradient>\n"
        "</defs>\n"
        "\n"
        "<circle cx='100' cy='100' r='99' style='fill:#FFFFFF;stroke:none; opacity:0.2;'/>\n"
        "<path d='M 100,20 A80,80 0, LARGE_ARC_FLAG, SWEEP_FLAG, END_X,END_Y' style='fill:none; stroke:url(#greenGradient); stroke-width:38;' />\n"
        "<path d='M 100,20 A80,80 0, LARGE_ARC_FLAG, SWEEP_FLAG, END_X,END_Y' style='fill:none; stroke:red; stroke-width:38; opacity:RED_OPACITY' />\n"
        "\n"
        " STATE_MARKER\n"
        "\n"
        "</svg>";

    static QString filledCircle   = "<circle cx='100' cy='100' r='35'/>";
    static QString plus           = "<path d='M 60,100 L140,100 M100,60 L100,140' style='stroke:black; stroke-width:30;'/>";
    static QString minus          = "<path d='M 60,100 L140,100' style='stroke:black; stroke-width:30;'/>";
    static QString hollowCircle   = "<circle cx='100' cy='100' r='30' style='fill:none;stroke:black;stroke-width:10'/>";

    QString svg = svg_template;

    if (chargeLevel > 99)
        chargeLevel = 99;

    double angle;
    QString sweepFlag;
    if (state == Solid::Battery::Discharging)
    {
        angle = M_PI_2 + 2 * M_PI * chargeLevel/100;
        sweepFlag = "0";
    }
    else
    {
        angle = M_PI_2 - 2 *M_PI * chargeLevel/100;
        sweepFlag = "1";
    }
    double circle_endpoint_x = 80.0 * cos(angle) + 100;
    double circle_endpoint_y = -80.0 * sin(angle) + 100;

    QString largeArgFlag = chargeLevel > 50 ? "1" : "0";

    svg.replace(QString("END_X"), QString::number(circle_endpoint_x));
    svg.replace(QString("END_Y"), QString::number(circle_endpoint_y));
    svg.replace(QString("LARGE_ARC_FLAG"), largeArgFlag);
    svg.replace(QString("SWEEP_FLAG"), sweepFlag);

    switch (state)
    {
    case Solid::Battery::FullyCharged:
        svg.replace("STATE_MARKER", filledCircle);
        break;
    case Solid::Battery::Charging:
        svg.replace("STATE_MARKER", plus);
        break;
    case Solid::Battery::Discharging:
        svg.replace("STATE_MARKER", minus);
        break;
    default:
        svg.replace("STATE_MARKER", hollowCircle);
    }

    if (state != Solid::Battery::FullyCharged && state != Solid::Battery::Charging &&  chargeLevel < mSettings.getPowerLowLevel() + 30)
    {
        if (chargeLevel <= mSettings.getPowerLowLevel() + 10)
            svg.replace("RED_OPACITY", "1");
        else
            svg.replace("RED_OPACITY", QString::number((mSettings.getPowerLowLevel() + 30 - chargeLevel)/20.0));
    }
    else
        svg.replace("RED_OPACITY", "0");

    // qDebug() << svg;

    // Paint the svg on a pixmap and create an icon from that.
    QSvgRenderer render(svg.toLatin1());
    QPixmap pixmap(render.defaultSize());
    pixmap.fill(QColor(0,0,0,0));
    QPainter painter(&pixmap);
    render.render(&painter);
    return QIcon(pixmap);
}
