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

#include "commandline.h"
#include "config.h"
#include "log.h"
#include "mainwindow.h"
#include "mod.h"
#include "plugins.h"
#include "utils.h"
#include "version.h"
#include "actions/bootentry.h"

#ifdef Q_OS_WIN32
	#include "udialog.h"
#endif // Q_OS_WIN32

#include <QDebug>

#ifdef KS_PURE_QT
	#include <QLibraryInfo>
	#include <QTranslator>
#else
	#include <KAboutData>
	#include <KCrash>
	#include <KDBusService>
#endif // KS_PURE_QT

// TODO: move more things to commandline.*
bool commonStartup(const QStringList &arguments, const QCommandLineOption &versionOption, const bool first, const bool forceShow) {
// FIXME: warning: QCommandLineParser: argument list cannot be empty, it should contain at least the executable name
//        in single instance mode
	if (!CLI::getArgs()->parse(arguments))
		qWarning() << CLI::getArgs()->errorText();

	if (CLI::getArgs()->isSet(versionOption)) {
		QString text = Utils::getApplicationVersionInfo() + "\n";
		text += Utils::getQtVersionInfo() + "\n";
		text += "Build Type: " + Utils::getBuildTypeInfo() + "\n";
		text += "System: " + Utils::getSystemInfo();

#ifdef Q_OS_WIN32
		UDialog::info(0, text, Qt::PlainText);
#else
		Utils::println(text);
#endif // Q_OS_WIN32

		return false;
	}

	if (first) {
		Mod::init();
		PluginManager::readConfig();
	}

	if (CLI::check()) {
		if (first)
			qApp->quit();
			
		return false;
	}
		
	bool useTimeOption = TimeOption::isValid() && (TimeOption::action() != nullptr);
		
	if (!MainWindow::self()->maybeShow(forceShow)) {
		qApp->quit();

		return false;
	}

	if (useTimeOption)
		TimeOption::setupMainWindow();

// TODO: wayland <http://blog.martin-graesslin.com/blog/2015/07/porting-qt-applications-to-wayland/>
	if (!first)
		MainWindow::self()->raise();

	return true;
}

void initAboutData(const QString &appDescription) {
#ifdef KS_KF5
	KAboutData about(
		"kshutdown", // app name - used in config file name etc.
		"KShutdown", // program display name
		KS_APP_VERSION
	);

	about.setBugAddress(KS_CONTACT.toUtf8());

	about.setCopyrightStatement(KS_COPYRIGHT);
	about.setHomepage(KS_HOME_PAGE);
	about.setLicense(KAboutLicense::GPL_V2);

/* FIXME: missing D-Bus interfaces that existed in KDE4/Qt4 (documented in Wiki):
qdbus net.sf.kshutdown /MainApplication quit
qdbus net.sf.kshutdown /kshutdown/main_window hide
*/
	about.setDesktopFileName("kshutdown");
// TODO: update wiki docs
	about.setOrganizationDomain("sf.net"); // changed to "net.sf.kshutdown" because default is "org.kde.kshutdown"

	about.setShortDescription(appDescription);

	about.addAuthor("Konrad Twardowski", i18n("Maintainer"), ""/* email */, KS_CONTACT);
	about.addCredit(i18n("Thanks To All!"), QString(), QString(), "https://sourceforge.net/p/kshutdown/wiki/Credits/");

	KAboutData::setApplicationData(about);
#else
	Q_UNUSED(appDescription)
#endif // KS_KF5
}

void initAppProperties() {
	QApplication::setApplicationName("KShutdown"); // used as file name in ~/.config/kshutdown.sf.net/KShutdown.conf
	QApplication::setApplicationDisplayName("KShutdown"); // no i18n
	QApplication::setApplicationVersion(KS_APP_VERSION);

	// NOTE: do not modify!
	#ifdef KS_PURE_QT
	QApplication::setDesktopFileName("kshutdown");
	QApplication::setOrganizationName("kshutdown.sf.net"); // used as file name in ~/.config/kshutdown.sf.net/KShutdown.conf
	#endif // KS_PURE_QT

	#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
	QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton, true); // hide unused titlebar "?" button

	// TEST: kshutdown --scale 2
	QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
	#endif // QT_VERSION
}

void initTranslation() {
	#ifdef KS_PURE_QT
	QString lang = QLocale::system().name();

	#ifdef Q_OS_WIN32
	auto *qtTranslator = new QTranslator();
	if (qtTranslator->load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
		qApp->installTranslator(qtTranslator);
	#endif // Q_OS_WIN32

	auto *kshutdownTranslator = new QTranslator();
	// NOTE: It uses QLocale::uiLanguages() which on Windows is not what we really want:
	//if (kshutdownTranslator->load(locale, "kshutdown", "_", ":/i18n"))
	if (kshutdownTranslator->load("kshutdown_" + lang, ":/i18n"))
		qApp->installTranslator(kshutdownTranslator);
	#else
	KLocalizedString::setApplicationDomain("kshutdown");
	#endif // KS_PURE_QT
}

int main(int argc, char **argv) {
	CLI::initBeforeApp(argc, argv);

/* TODO: GTK style (?)
	#ifdef KS_PURE_QT
	#ifndef Q_OS_WIN32
	bool userStyle = false;
	#endif // !Q_OS_WIN32
	if (argc > 1) {
		for (int i = 1; i < argc; i++) {
			QString arg(argv[i]);
			#ifndef Q_OS_WIN32
			if ((arg == "-style") || (arg == "--style")) {
				userStyle = true;
			
				break; // for
			}
			#endif // !Q_OS_WIN32
		}
	}
	#endif // KS_PURE_QT

	qDebug() << QStyleFactory::keys();

	#ifndef Q_OS_WIN32
	if (
		!userStyle && // do not override user style option
		Utils::isGTKStyle() &&
		!Utils::isHaiku()
	) {
		QStyle *gtkStyle = QStyleFactory::create("gtk+");
		if (gtkStyle)
			QApplication::setStyle(gtkStyle);
	}
	#endif // !Q_OS_WIN32
*/

	// init misc

	Log::init();
	Utils::init();
	initAppProperties();

	QApplication program(argc, argv);

	#ifdef KS_KF5
	// CREDITS: based on https://cgit.kde.org/okular.git/commit/?id=1904f7e95e68ded874cdbe7d9685fe2cd05795b0
	KCrash::initialize();
	#endif // KS_KF5

	initTranslation(); // 1.
	QString appDescription = i18n("A graphical shutdown utility"); // 2.

	initAboutData(appDescription);

/* TEST: KCrash handler
	QObject *crash = nullptr;
	crash->objectName();
*/

// TODO: about.setTranslator(ki18n("Your names"), ki18n("Your emails"));

	qDebug()
		<< "Version:"
		<< Utils::getApplicationVersionInfo()
		<< Utils::getQtVersionInfo();
	qDebug()
		<< "Build Type:"
		<< Utils::getBuildTypeInfo();

	CLI::init(appDescription); // 1.
	Config::init(); // 2.
	BootEntry::initFromConfig(); // after Config::init
	PluginManager::initActionsAndTriggers(); // 3.

	// init command line options

	CLI::initOptions();
	// NOTE: clash with -h: parser->addHelpOption();
	QCommandLineOption versionOption = CLI::getArgs()->addVersionOption();

	// init single-instance handler

	#ifdef KS_KF5
	auto *dbusService = new KDBusService(KDBusService::Unique | KDBusService::NoExitOnFailure);
// TODO: print message if KShutdown is already running
// qDebug("KShutdown is already running");

	QObject::connect(dbusService, &KDBusService::activateRequested, [&versionOption](const QStringList &arguments, [[maybe_unused]] const QString &cwd) {
		commonStartup(arguments, versionOption, false, true);

		if (CLI::isArg("cancel"))
			MainWindow::self()->setActive(false);
	});
	#endif // KS_KF5

	// start the application

	static bool first = true;

	if (!commonStartup(QApplication::arguments(), versionOption, first, false))
		return 0;

	first = false;

	return QApplication::exec();
}
