/*
	main.cpp - KShutDown
	Copyright (C) 2003  Konrad Twardowski <kdtonline@poczta.onet.pl>

	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 2 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, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "actions.h"
#include "configuration.h"
#include "extras.h"
#include "miscutils.h"
#include "mmainwindow.h"
#include "msystemtray.h"

#include <tqfileinfo.h>

#include <tdeaboutdata.h>
#include <tdecmdlineargs.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kuniqueapplication.h>

// 0.1.x, 0.3.x, etc - Unstable, Beta
// 0.2.x, 0.4.x, etc - Stable
const char* version = "1.0.4";

TDEAboutData aboutData(
	"kshutdown", // internal name
	"KShutDown", // full name
	version,
	I18N_NOOP("A Shut Down Utility for TDE"), // description
	TDEAboutData::License_GPL_V2, // license
	"(C) 2003-3000 Konrad Twardowski", // copyright
	"", // text
	"http://kshutdown.sourceforge.net/", // project page
	"kdtonline@poczta.onet.pl" // bugs
);

static TDECmdLineOptions options[] =
{
	{ "s", 0, 0 },
	{ "shutdown", I18N_NOOP("Turn off computer"), 0 },
	{ "h", 0, 0 },
	{ "halt", I18N_NOOP("Turn off computer"), 0 },
	{ "r", 0, 0 },
	{ "reboot", I18N_NOOP("Restart computer"), 0 },
	{ "k", 0, 0 },
	{ "lock", I18N_NOOP("Lock session"), 0 },
	{ "l", 0, 0 },
	{ "logout", I18N_NOOP("End current session"), 0 },
	{ "e", 0, 0 },
	{ "extra <file>", I18N_NOOP("Execute \"Extras\" command (.desktop file)"), 0 },
	{ "confirm", I18N_NOOP("Confirm command line action"), 0 },
	{ "standard", I18N_NOOP("Show standard logout dialog"), 0 },
	{ "c", 0, 0 },
	{ "cancel", I18N_NOOP("Cancel an active action"), 0 },
	{ "init", I18N_NOOP("Don't show window at startup"), 0 },
	{ "test", I18N_NOOP("Enable test mode"), 0 },
	{ "default", I18N_NOOP("Disable test mode"), 0 },
	{ "+[time]", I18N_NOOP("Time; Examples: 01:30 - absolute time (HH:MM); " \
		"10 - number of minutes to wait from now"), 0 },
	TDECmdLineLastOption
};

/** @short KShutDown application. */
class KShutDownApplication: public KUniqueApplication
{
public:
	/**
	 * Constructor.
	 */
	KShutDownApplication()
		: KUniqueApplication(),
		_confirm(false),
		isTimeArg(false),
		now(false),
		timeArgIsValid(false),
		timeArg()
	{
	}

	/**
	 * Initializes the main window, and checks command line arguments.
	 */
	virtual int newInstance();
private:
	enum Mode {
		Mode_Visible = -1, // show the main window at startup
		Mode_Hidden = -2, // hide the main window at startup
		Mode_Ok = 0, // success
		Mode_Error = 1 // misc. failure
	};
	bool
		_confirm,
		isTimeArg,
		now,
		timeArgIsValid;
	TQString timeArg;
	int doExecAction(const Action::Type action);
	int doProcessArgs(const TDECmdLineArgs *args);
};

// public

int KShutDownApplication::newInstance()
{
	// autostart
	if (kapp->isRestored()) {
		TDEConfig *config = kapp->config();
		config->setGroup("KShutDown");
		if (!config->readBoolEntry("Autostart", false)) {
			quit();

			return 0;
		}
	}

	static bool doShow = false;
	bool doRaise = ks_main;

	// create main window (only one)
	if (!ks_main) {
		(void)new MMainWindow();
		kapp->setMainWidget(ks_main);
		connect(
			this, TQ_SIGNAL(aboutToQuit()),
			ks_main, TQ_SLOT(deleteLater()));
	}

	// check command line args
	TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
	int retval = doProcessArgs(args);
	args->clear();

	if (MSystemTray::mode() != MSystemTray::Always) {
		ks_main->show();
		if (doRaise)
			ks_main->makeVisible();
		doShow = true;

		return Mode_Ok;
	}

	// gui mode
	if ((retval == Mode_Visible) || (retval == Mode_Hidden)) {
		if ((retval == Mode_Visible) && (!kapp->isRestored() || doShow)) {
			ks_main->show();
			if (doRaise)
				ks_main->makeVisible();
		}
		doShow = true;

		return Mode_Ok;
	}

	return retval; // command line exit code
}

// private

int KShutDownApplication::doExecAction(const Action::Type action) {
	if (!ks_main)
		return Mode_Error;

	// use time arg.
	if (timeArgIsValid) {
		ks_main->cancel(); // cancel action (if any)
		if (!now) {
			ks_main->setAction(action);
			ks_main->start(_confirm);

			return Mode_Ok;
		}
	}

	if (_confirm) {
		if (ks_actions->execConfirm(action))
			return Mode_Ok;
	}
	else {
		if (ks_actions->exec(action, action != Action::LockScreen))
			return Mode_Ok;
	}
	MSystemTray::setMode((MSystemTray::Mode)kshutdownrc->systemTray);

	return Mode_Error;
}

int KShutDownApplication::doProcessArgs(const TDECmdLineArgs *args) {
	if (!ks_main)
		return Mode_Error;

	_confirm = args->isSet("confirm");
	isTimeArg = false;
	now = false;
	timeArg = "";
	timeArgIsValid = false;

	// read time arg.
	bool absoluteTime = false;
	int minutes = 0;
	TQDateTime dt = TQDateTime::currentDateTime();
	if (args->count()) {
		timeArg = args->arg(0); // first arg. is a "time" arg.
		if (!timeArg.isEmpty()) {
			isTimeArg = true;

			if (timeArg.upper() == "NOW") {
				now = true;
				timeArgIsValid = true;
			}
			else {
				bool ok = false;
				minutes = timeArg.toInt(&ok); // MM?
				if (ok) {
					if (minutes == 0) {
						now = true;
						timeArgIsValid = true;
					}
				}
				else {
					absoluteTime = true;
// FIXME: 2.0: AM/PM
					TQTime t = TQTime::fromString(timeArg);
					if (t.isValid() && !t.isNull()) { // HH:MM[:SS]?
						ok = true;
						dt.setTime(t);
					}
				}
				if (!ok || !dt.isValid() || dt.isNull()) {
					KMessageBox::error(
						0,
						MiscUtils::HTML(i18n("Invalid time: <b>%1</b>").arg(timeArg))
					);
				}
				else {
					timeArgIsValid = true;
				}
			}
		}
	}

	// test mode
	if (args->isSet("test"))
		ks_main->setTestMode(true);

	// normal mode
	if (args->isSet("default"))
		ks_main->setTestMode(false);

	// cancel
	if (args->isSet("cancel")) {
		ks_main->cancel();

		return Mode_Ok;
	}

	// standard logout dialog
	if (args->isSet("standard")) {
		kapp->requestShutDown(
			TDEApplication::ShutdownConfirmYes,
			TDEApplication::ShutdownTypeDefault,
			TDEApplication::ShutdownModeDefault
		);

		return Mode_Ok;
	}

	// do nothing ..
	if (isTimeArg && !timeArgIsValid)
		return Mode_Error;

	// setup main window
	if (timeArgIsValid) {
		if (!now) {
			if (MiscUtils::isRestricted("tab_time"))
				return Mode_Error;

			ks_main->cancel(); // cancel action before "setDelayType"
			if (absoluteTime)
			{
				ks_main->setDelayType(MMainWindow::DelayType_DateTime);
				ks_main->setDate(dt.date());
				ks_main->setTime(dt.time());
			}
			else
			{
				ks_main->setDelayType(MMainWindow::DelayType_TimeFromNow);
				ks_main->setTime(TQTime().addSecs(minutes * 60));
			}
		}
		ks_main->makeVisible();

		// exec action below ..
	}

	// extra
	if (args->isSet("extra")) {
		TQString extrasCommand = args->getOption("extra");
		if (!extrasCommand.isEmpty()) {
			TQFileInfo extra(extrasCommand);
			if (extra.exists()) {
				ks_extras->setAction(extra.filePath(), extra.baseName());
				
				return doExecAction(Action::Extras);
			}
			else {
				tqWarning("ERROR: File \"%s\" does not exist", extrasCommand.latin1());
			}
		}
	
		return Mode_Error;
	}

	// halt
	if (args->isSet("shutdown") || args->isSet("halt"))
		return doExecAction(Action::ShutDown);

	// reboot
	if (args->isSet("reboot"))
		return doExecAction(Action::Reboot);

	// lock
	if (args->isSet("lock"))
		return doExecAction(Action::LockScreen);

	// logout
	if (args->isSet("logout"))
		return doExecAction(Action::Logout);

	if (args->isSet("init"))
		return Mode_Hidden; // init window, but don't show it

	return Mode_Visible; // gui mode
}

// main

int main(int argc, char **argv)
{
// TODO: 2.0: init on demand?
	aboutData.addCredit("Konrad Twardowski", "Author, Maintainer", "kdtonline@poczta.onet.pl", "http://www.kdtonline.prv.pl/");
	aboutData.addCredit("Caryn \"Hellchick\" Law", "Female Quake III Arena Announcer Voice Files", "hellchick ( at ) planetquake.com", "http://www.planetquake.com/voxfeminae/");
	aboutData.addCredit("Arend van Beelen jr.", "Ideas", "", "http://www.liacs.nl/~dvbeelen");
	aboutData.addCredit("Bram Schoenmakers", "Dutch translation", "bram_s ( at ) softhome.net");
	aboutData.addCredit("Charles Barcza", "Hungarian translation, blackPanther-Linux RPM", "kbarcza ( at ) blackpanther.hu", "http://www.blackpanther.hu/");
	aboutData.addCredit("Daniel Nylander", "Swedish translation");
	aboutData.addCredit("Elias Probst", "Gentoo ebuilds, German translation", "elias.probst ( at ) gmx.de");
	aboutData.addCredit("Giovanni Venturi", "Italian translation", "jumpyj ( at ) tiscali.it");
	aboutData.addCredit("Gregorio Guidi", "Patches");
	aboutData.addCredit("Guido Tack", "Ideas", "", "http://www.ps.uni-sb.de/~tack");
	aboutData.addCredit("Jozef Riha", "Slovak translation", "zefo ( at ) seznam.cz");
	aboutData.addCredit("Karol Adamczyk [rampage]", "Gentoo ebuild");
	aboutData.addCredit("Matrix", "SuSE RPM", "matrix ( at ) ehelp.pl");
	aboutData.addCredit("Michael Goettsche", "Bug reports");
	aboutData.addCredit("Paulo Zambon", "Portuguese Brazil translation", "pzambon ( at ) astornet.com.br");
	aboutData.addCredit("Philipp Weissenbacher");
	aboutData.addCredit("Piotr Budny");
	aboutData.addCredit("Quique", "Spanish translation", "tquique ( at ) sindominio.net");
	aboutData.addCredit("Robert Kratky", "Czech translation", "kratky ( at ) rob.cz");
	aboutData.addCredit("Romain Beauxis", "Debian Package", "", "http://www.cti.ecp.fr/~beauxir5/debian/");
	aboutData.addCredit("Spider (ALT Linux)", "Russian translation");
	aboutData.addCredit("Stephen Ellwood", "Panel Applet, User Interface");
	aboutData.addCredit("Zdenko Podobny", "Slovak translation, Mandrake RPM", "zdpo ( at ) mailbox.sk");
	aboutData.addCredit("KDE-APPS.org", "", "", "http://www.kde-apps.org/");
	aboutData.addCredit("Lock/Logout Applet Team");
	aboutData.addCredit("SourceForge.net", "", "", "http://www.sourceforge.net/");

	// init command line
	TDECmdLineArgs::init(argc, argv, &aboutData);
	TDECmdLineArgs::addCmdLineOptions(options);

	if (!KUniqueApplication::start())
		return 0;

	// init application
	KShutDownApplication software;

	// main loop
	return software.exec();
}
