// SPDX-FileCopyrightText: 2007, 2009 Klarälvdalens Datakonsult AB
// SPDX-License-Identifier: GPL-2.0-or-later

#include "systemtrayicon.h"

#include "gpgol_client_debug.h"
#include "websocketclient.h"

#include <QCoreApplication>
#include <QEvent>
#include <QMenu>
#include <QPointer>
#include <QTimer>
#include <QWidget>

#include <KAboutApplicationDialog>
#include <KAboutData>
#include <KLocalizedString>

static const int ATTENTION_ANIMATION_FRAMES_PER_SEC = 1;

class SystemTrayIcon::Private
{
    friend class ::SystemTrayIcon;
    SystemTrayIcon *const q;

public:
    explicit Private(SystemTrayIcon *qq);
    ~Private();

private:
    bool attentionWanted() const
    {
        return attentionAnimationTimer.isActive();
    }

    void setAttentionWantedImpl(bool on)
    {
        if (on) {
            attentionAnimationTimer.start();
        } else {
            attentionAnimationTimer.stop();
            attentionIconShown = false;
            q->setIcon(normalIcon);
        }
    }

    void slotActivated(ActivationReason reason)
    {
        if (reason == QSystemTrayIcon::Trigger) {
            q->doActivated();
        }
    }

    void slotAttentionAnimationTimerTimout()
    {
        if (attentionIconShown) {
            attentionIconShown = false;
            q->setIcon(normalIcon);
        } else {
            attentionIconShown = true;
            q->setIcon(attentionIcon);
        }
    }

private:
    bool attentionIconShown;

    QMenu menu;
    QIcon normalIcon, attentionIcon;

    QTimer attentionAnimationTimer;

    QPointer<QWidget> mainWindow;
    QPointer<QWidget> attentionWindow;
    QAction aboutAction;
    QAction quitAction;
    KAboutApplicationDialog *aboutDialog = nullptr;
};

SystemTrayIcon::Private::Private(SystemTrayIcon *qq)
    : q(qq)
    , attentionIconShown(false)
    , attentionAnimationTimer()
    , mainWindow()
    , attentionWindow()
    , aboutAction(QIcon::fromTheme(QStringLiteral("kleopatra")),
                  xi18nc("@action:inmenu", "&About <application>%1</application>...", KAboutData::applicationData().displayName()),
                  q)
    , quitAction(QIcon::fromTheme(QStringLiteral("application-exit")),
                 xi18nc("@action:inmenu", "&Shutdown <application>%1</application>", KAboutData::applicationData().displayName()),
                 q)
{
    Q_SET_OBJECT_NAME(attentionAnimationTimer);
    Q_SET_OBJECT_NAME(aboutAction);
    Q_SET_OBJECT_NAME(quitAction);

    attentionAnimationTimer.setSingleShot(false);
    attentionAnimationTimer.setInterval(1000 * ATTENTION_ANIMATION_FRAMES_PER_SEC / 2);

    menu.addAction(&aboutAction);
    menu.addAction(&quitAction);
    q->setContextMenu(&menu);

    connect(q, &QSystemTrayIcon::activated, q, [this](QSystemTrayIcon::ActivationReason reason) {
        slotActivated(reason);
    });
    connect(&attentionAnimationTimer, &QTimer::timeout, q, [this]() {
        slotAttentionAnimationTimerTimout();
    });

    connect(&aboutAction, &QAction::triggered, q, &SystemTrayIcon::slotAbout);
    connect(&quitAction, &QAction::triggered, QCoreApplication::instance(), &QCoreApplication::quit);

    q->setToolTip(WebsocketClient::self().stateDisplay());
}

SystemTrayIcon::Private::~Private()
{
}

SystemTrayIcon::SystemTrayIcon(QObject *p)
    : QSystemTrayIcon(p)
    , d(std::make_unique<Private>(this))
{
}

SystemTrayIcon::SystemTrayIcon(const QIcon &icon, QObject *p)
    : QSystemTrayIcon(icon, p)
    , d(std::make_unique<Private>(this))
{
    d->normalIcon = d->attentionIcon = icon;
}

SystemTrayIcon::~SystemTrayIcon() = default;

void SystemTrayIcon::setMainWindow(QWidget *mw)
{
    if (d->mainWindow) {
        return;
    }
    d->mainWindow = mw;
    if (mw) {
        mw->installEventFilter(this);
    }
    doMainWindowSet(mw);
    slotEnableDisableActions();
}

QWidget *SystemTrayIcon::mainWindow() const
{
    return d->mainWindow;
}

void SystemTrayIcon::setAttentionWindow(QWidget *mw)
{
    if (d->attentionWindow) {
        return;
    }
    d->attentionWindow = mw;
    if (mw) {
        mw->installEventFilter(this);
    }
    slotEnableDisableActions();
}

QWidget *SystemTrayIcon::attentionWindow() const
{
    return d->attentionWindow;
}

bool SystemTrayIcon::eventFilter(QObject *o, QEvent *e)
{
    if (o == d->mainWindow)
        switch (e->type()) {
        case QEvent::Close:
            doMainWindowClosed(static_cast<QWidget *>(o));
            // fall through:
            [[fallthrough]];
        case QEvent::Show:
        case QEvent::DeferredDelete:
            QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection);
        default:;
        }
    else if (o == d->attentionWindow)
        switch (e->type()) {
        case QEvent::Close:
            doAttentionWindowClosed(static_cast<QWidget *>(o));
            // fall through:
            [[fallthrough]];
        case QEvent::Show:
        case QEvent::DeferredDelete:
            QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection);
        default:;
        }
    return false;
}

void SystemTrayIcon::setAttentionWanted(bool on)
{
    if (d->attentionWanted() == on) {
        return;
    }
    qCDebug(GPGOL_CLIENT_LOG) << d->attentionWanted() << "->" << on;
    d->setAttentionWantedImpl(on);
}

bool SystemTrayIcon::attentionWanted() const
{
    return d->attentionWanted();
}

void SystemTrayIcon::setNormalIcon(const QIcon &icon)
{
    if (d->normalIcon.cacheKey() == icon.cacheKey()) {
        return;
    }
    d->normalIcon = icon;
    if (!d->attentionWanted() || !d->attentionIconShown) {
        setIcon(icon);
    }
}

QIcon SystemTrayIcon::normalIcon() const
{
    return d->normalIcon;
}

void SystemTrayIcon::setAttentionIcon(const QIcon &icon)
{
    if (d->attentionIcon.cacheKey() == icon.cacheKey()) {
        return;
    }
    d->attentionIcon = icon;
    if (d->attentionWanted() && d->attentionIconShown) {
        setIcon(icon);
    }
}

QIcon SystemTrayIcon::attentionIcon() const
{
    return d->attentionIcon;
}

void SystemTrayIcon::doMainWindowSet(QWidget *)
{
}
void SystemTrayIcon::doMainWindowClosed(QWidget *)
{
}
void SystemTrayIcon::doAttentionWindowClosed(QWidget *)
{
}

void SystemTrayIcon::slotAbout()
{
    if (!d->aboutDialog) {
        d->aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData());
        d->aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
    }

    if (d->aboutDialog->isVisible()) {
        d->aboutDialog->raise();
    } else {
        d->aboutDialog->show();
    }
}

void SystemTrayIcon::slotEnableDisableActions()
{
}

void SystemTrayIcon::doActivated()
{
    Q_ASSERT(mainWindow());
    if (mainWindow()->isVisible()) {
        mainWindow()->hide();
    } else {
        mainWindow()->show();
        mainWindow()->raise();
    }
}

void SystemTrayIcon::slotStateChanged()
{
    setToolTip(WebsocketClient::self().stateDisplay());
}

#include "moc_systemtrayicon.cpp"
