// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2012 Konrad Twardowski

#include "usystemtray.h"

#include "config.h"
#include "mainwindow.h"
#include "utils.h"

#include <QDebug>
#include <QPainter>

// TODO: better support for dock(ish) taskbars (Windows 7/Unity)

// public:

USystemTray::USystemTray(MainWindow *mainWindow)
	: QObject(mainWindow)
{
	#ifdef KS_PURE_QT
	m_sessionRestored = qApp->isSessionRestored();
	#endif // KS_PURE_QT

	qDebug() << "USystemTray::isSupported:" << isSupported();
}

void USystemTray::info(const QString &message) const {
	if (m_trayIcon == nullptr)
		return;

	const milliseconds timeout = 5s; // use shorter timeout for less important notifications

	#ifdef KS_KF5
	m_trayIcon->showMessage(QApplication::applicationDisplayName(), message, "dialog-information", timeout.count());
	#else
	m_trayIcon->showMessage(QApplication::applicationDisplayName(), message, QSystemTrayIcon::Information, timeout.count());
	#endif // KS_KF5
}

bool USystemTray::isSupported() const {
	#ifdef KS_KF5
	return true; // assume the Desktop Environment is sane
	#else
	return
		QSystemTrayIcon::isSystemTrayAvailable() &&
		// HACK: MATE launches KShutdown before system tray panel is created
		!(Utils::mate && m_sessionRestored);
	#endif // KS_KF5
}

QPixmap USystemTray::makeIcon(const QIcon &baseIcon, const int size, const bool custom, const bool active, const QColor &normalColor, const QColor &activeColor) {
	QPixmap pixmap = baseIcon.pixmap(size);

	if (!active && !custom)
		return pixmap;

	QColor tintColor = active ? activeColor : normalColor;
	int tintH;
	int tintS;
	int tintL;
	tintColor.getHsl(&tintH, &tintS, &tintL);

	QColor temp;
	QImage image = pixmap.toImage();
	const int iw = image.width();
	const int ih = image.height();

	for (int y = 0; y < ih; y++) {
		for (int x = 0; x < iw; x++) {
			QRgb rgb = image.pixel(x, y);

			// invisible pixel, skip
			if (rgb == 0)
				continue; // for

			// convert RGB to HSL
			temp.setRgba(rgb);

			int h;
			int s;
			int l;
			temp.getHsl(&h, &s, &l);

			if (custom)
				h = tintH;
			else
				h = 42; // ~orange

			// convert back to RGBA
			temp.setHsl(h, s, l, qAlpha(rgb));

			image.setPixelColor(x, y, temp);
		}
	}

	return QPixmap::fromImage(image);
}

void USystemTray::setToolTip(const QString &toolTip) {
	m_toolTip = toolTip; // save "toolTip" value for later use

	if (m_trayIcon == nullptr)
		return;

	#ifdef KS_KF5
	m_trayIcon->setToolTipTitle(QApplication::applicationDisplayName());
// FIXME: "flickering" if countdown is active
	m_trayIcon->setToolTipSubTitle(
		(toolTip == m_trayIcon->toolTipTitle())
		? ""
		: QString(toolTip).replace("<qt>KShutdown<br><br>", "<qt>") // remove leading/duplicated "KShutdown" text
	);
	#else
	m_trayIcon->setToolTip(toolTip);
	#endif // KS_KF5
}

void USystemTray::setVisible(const bool visible) {
	#ifdef KS_PURE_QT
	m_sessionRestored = false; // clear flag
	#endif // KS_PURE_QT

	auto *mainWindow = getMainWindow();

	if (visible && (m_trayIcon == nullptr)) {
		qDebug() << "Show system tray";

#ifdef KS_KF5
		#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
		m_trayIcon = new KStatusNotifierItem();

		connect(m_trayIcon, &KStatusNotifierItem::activateRequested, [this](bool active, const QPoint &) {
			if (active)
				getMainWindow()->showOrHide();
		});
		#else
		m_trayIcon = new KStatusNotifierItem(mainWindow);
		#endif // QT_VERSION

// FIXME: Ubuntu 17.10/Unity: mouse click behavior is a total mess
		m_trayIcon->setCategory(KStatusNotifierItem::ApplicationStatus);
		m_trayIcon->setStandardActionsEnabled(false);
// FIXME: m_trayIcon->setToolTipIconByPixmap(QIcon(":/images/kshutdown.png"));
		m_trayIcon->setToolTipIconByName("kshutdown");
#else
		m_trayIcon = new QSystemTrayIcon(mainWindow);

		connect(
			m_trayIcon, &QSystemTrayIcon::activated,
			[this](const QSystemTrayIcon::ActivationReason reason) {
				if (reason == QSystemTrayIcon::Trigger) {
					getMainWindow()->showOrHide();
				}
			}
		);
#endif // KS_KF5

		auto *menu = new QMenu();
		mainWindow->initFileMenu(menu, false);
		m_trayIcon->setContextMenu(menu);

		updateIcon();

		if (!m_toolTip.isNull()) {
			//qDebug() << "Init tool tip:" << m_toolTip;
			setToolTip(m_toolTip);
		}

		#ifdef KS_PURE_QT
		m_trayIcon->show(); // after setIcon
		#endif // KS_PURE_QT
	}
	else if (!visible && (m_trayIcon != nullptr)) {
		qDebug() << "Hide system tray";

		delete m_trayIcon;
		m_trayIcon = nullptr;
	}
}

// TODO: revisit overlay icons
void USystemTray::updateIcon() {
	if (m_trayIcon == nullptr)
		return;

	QIcon appIcon = QApplication::windowIcon();

	#ifndef KS_KF5
	const bool active = getMainWindow()->active();

	// HACK: We need to show an empty system tray icon first
	// to fix wrong icon alignment and background repaint issues...
	if (m_applyIconHack) {
		m_applyIconHack = false;
		if (Utils::mate && Config::systemTrayIconEnabled) {
			//qDebug() << "Apply icon hack";
			m_trayIcon->setIcon(appIcon); // suppress Qt warning
			m_trayIcon->show();
		}
	}
	#endif // !KS_KF5
	
	// get base icon

#ifdef KS_KF5
// TODO: option
	QString iconName = Utils::isKDE() ? "system-shutdown" : "kshutdown";

	QIcon testIcon = QIcon::fromTheme(iconName);
	if (testIcon.isNull()) {
		qDebug() << "(1) System theme icon" << iconName << "not found in" << testIcon.themeName();
		m_trayIcon->setIconByPixmap(appIcon); // fallback
	}
	else {
		m_trayIcon->setIconByName(iconName);
	}

/* TODO: hide if inactive #5.x
	bool active = mainWindow->active();
	m_trayIcon->setStatus(active ? KStatusNotifierItem::Active : KStatusNotifierItem::Passive);
*/
#else
	// convert base icon to pixmap

	QIcon icon = appIcon;

	#ifndef Q_OS_WIN32
	if (!active && Config::systemTrayIconUseTheme) {
		QString iconName = "system-shutdown";
		icon = QIcon::fromTheme(iconName);
		if (icon.isNull()) {
			qDebug() << "(2) System theme icon" << iconName << "not found in" << icon.themeName();
			icon = appIcon; // fallback
		}
		// HACK: fixes https://sourceforge.net/p/kshutdown/bugs/27/
		else {
			m_trayIcon->setIcon(icon);

			return; // no image effects
		}
	}
	#endif // !Q_OS_WIN32

	m_trayIcon->setIcon(makeIcon(
		icon, 64_px,
		Config::systemTrayIconCustomColor.getBool(),
		active,
		Config::systemTrayIconNormalColor.getColor(),
		Config::systemTrayIconActiveColor.getColor()
	));
#endif // KS_KF5
}

void USystemTray::warning(const QString &message) const {
	if (m_trayIcon == nullptr)
		return;

	#ifdef KS_KF5
	m_trayIcon->showMessage(QApplication::applicationDisplayName(), message, "dialog-warning");
	#else
	m_trayIcon->showMessage(QApplication::applicationDisplayName(), message, QSystemTrayIcon::Warning);
	#endif // KS_KF5
}

// private:

MainWindow *USystemTray::getMainWindow() {
	return static_cast<MainWindow *>(parent());
}
