/*
 *  kalarmapp.h  -  the KAlarm application object
 *  Program:  kalarm
 *  Copyright © 2001-2008 by David Jarvie <djarvie@kde.org>
 *
 *  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.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef KALARMAPP_H
#define KALARMAPP_H

/** @file kalarmapp.h - the KAlarm application object */

#include <tqguardedptr.h>
class TQTimer;
class TQDateTime;

#include <kuniqueapplication.h>
#include <kurl.h>
class TDEProcess;
namespace KCal { class Event; }

#include "alarmevent.h"
class DcopHandler;
#ifdef OLD_DCOP
class DcopHandlerOld;
#endif
class AlarmCalendar;
class MainWindow;
class AlarmListView;
class MessageWin;
class TrayWindow;
class ShellProcess;


class KAlarmApp : public KUniqueApplication
{
		Q_OBJECT
  
	public:
		~KAlarmApp();
		virtual int        newInstance();
		static KAlarmApp*  getInstance();
		bool               checkCalendarDaemon()           { return initCheck(); }
		bool               haveSystemTray() const          { return mHaveSystemTray; }
		bool               wantRunInSystemTray() const;
		bool               alarmsDisabledIfStopped() const { return mDisableAlarmsIfStopped; }
		bool               speechEnabled() const           { return mSpeechEnabled; }
		bool               korganizerEnabled() const       { return mKOrganizerEnabled; }
		bool               restoreSession();
		bool               sessionClosingDown() const      { return mSessionClosingDown; }
		void               quitIf()                        { quitIf(0); }
		void               doQuit(TQWidget* parent);
		static void        displayFatalError(const TQString& message);
		void               addWindow(TrayWindow* w)        { mTrayWindow = w; }
		void               removeWindow(TrayWindow*);
		TrayWindow*        trayWindow() const              { return mTrayWindow; }
		MainWindow*        trayMainWindow() const;
		bool               displayTrayIcon(bool show, MainWindow* = 0);
		bool               trayIconDisplayed() const       { return !!mTrayWindow; }
		bool               editNewAlarm(MainWindow* = 0);
		virtual void       commitData(TQSessionManager&);

		void*              execAlarm(KAEvent&, const KAAlarm&, bool reschedule, bool allowDefer = true, bool noPreAction = false);
		void               alarmShowing(KAEvent&, KAAlarm::Type, const DateTime&);
		void               alarmCompleted(const KAEvent&);
		bool               deleteEvent(const TQString& eventID)         { return handleEvent(eventID, EVENT_CANCEL); }
		void               commandMessage(ShellProcess*, TQWidget* parent);
		// Methods called indirectly by the DCOP interface
		bool               scheduleEvent(KAEvent::Action, const TQString& text, const TQDateTime&,
		                                 int lateCancel, int flags, const TQColor& bg, const TQColor& fg,
		                                 const TQFont&, const TQString& audioFile, float audioVolume,
		                                 int reminderMinutes, const KARecurrence& recurrence,
						 int repeatInterval, int repeatCount,
		                                 uint mailFromID = 0, const EmailAddressList& mailAddresses = EmailAddressList(),
		                                 const TQString& mailSubject = TQString(),
		                                 const TQStringList& mailAttachments = TQStringList());
		bool               handleEvent(const TQString& calendarFile, const TQString& eventID)    { return handleEvent(calendarFile, eventID, EVENT_HANDLE); }
		bool               triggerEvent(const TQString& calendarFile, const TQString& eventID)   { return handleEvent(calendarFile, eventID, EVENT_TRIGGER); }
		bool               deleteEvent(const TQString& calendarFile, const TQString& eventID)    { return handleEvent(calendarFile, eventID, EVENT_CANCEL); }
	public slots:
		void               processQueue();
	signals:
		void               trayIconToggled();
	protected:
		KAlarmApp();
	private slots:
		void               quitFatal();
		void               slotPreferencesChanged();
		void               slotCommandOutput(TDEProcess*, char* buffer, int bufflen);
		void               slotLogProcExited(ShellProcess*);
		void               slotCommandExited(ShellProcess*);
		void               slotSystemTrayTimer();
		void               slotExpiredPurged();
	private:
		enum EventFunc
		{
			EVENT_HANDLE,    // if the alarm is due, execute it and then reschedule it
			EVENT_TRIGGER,   // execute the alarm regardless, and then reschedule it if it already due
			EVENT_CANCEL     // delete the alarm
		};
		struct ProcData
		{
			ProcData(ShellProcess* p, ShellProcess* logp, KAEvent* e, KAAlarm* a, int f = 0);
			~ProcData();
			enum { PRE_ACTION = 0x01, POST_ACTION = 0x02, RESCHEDULE = 0x04, ALLOW_DEFER = 0x08,
			       TEMP_FILE = 0x10, EXEC_IN_XTERM = 0x20 };
			bool                 preAction() const   { return flags & PRE_ACTION; }
			bool                 postAction() const  { return flags & POST_ACTION; }
			bool                 reschedule() const  { return flags & RESCHEDULE; }
			bool                 allowDefer() const  { return flags & ALLOW_DEFER; }
			bool                 tempFile() const    { return flags & TEMP_FILE; }
			bool                 execInXterm() const { return flags & EXEC_IN_XTERM; }
			ShellProcess*             process;
			TQGuardedPtr<ShellProcess> logProcess;
			KAEvent*                  event;
			KAAlarm*                  alarm;
			TQGuardedPtr<TQWidget>      messageBoxParent;
			TQStringList               tempFiles;
			int                       flags;
		};
		struct DcopTQEntry
		{
			DcopTQEntry(EventFunc f, const TQString& id) : function(f), eventId(id) { }
			DcopTQEntry(const KAEvent& e, EventFunc f = EVENT_HANDLE) : function(f), event(e) { }
			DcopTQEntry() { }
			EventFunc  function;
			TQString    eventId;
			KAEvent    event;
		};

		bool               initCheck(bool calendarOnly = false);
		void               quitIf(int exitCode, bool force = false);
		void               redisplayAlarms();
		bool               checkSystemTray();
		void               changeStartOfDay();
		void               setUpDcop();
		bool               handleEvent(const TQString& calendarFile, const TQString& eventID, EventFunc);
		bool               handleEvent(const TQString& eventID, EventFunc);
		void               rescheduleAlarm(KAEvent&, const KAAlarm&, bool updateCalAndDisplay);
		void               cancelAlarm(KAEvent&, KAAlarm::Type, bool updateCalAndDisplay);
		ShellProcess*      doShellCommand(const TQString& command, const KAEvent&, const KAAlarm*, int flags = 0);
		TQString            createTempScriptFile(const TQString& command, bool insertShell, const KAEvent&, const KAAlarm&);
		void               commandErrorMsg(const ShellProcess*, const KAEvent&, const KAAlarm*, int flags = 0);

		static KAlarmApp*     theInstance;          // the one and only KAlarmApp instance
		static int            mActiveCount;         // number of active instances without main windows
		static int            mFatalError;          // a fatal error has occurred - just wait to exit
		static TQString        mFatalMessage;        // fatal error message to output
		bool                  mInitialised;         // initialisation complete: ready to handle DCOP calls
		DcopHandler*          mDcopHandler;         // the parent of the main DCOP receiver object
#ifdef OLD_DCOP
		DcopHandlerOld*       mDcopHandlerOld;      // the parent of the old main DCOP receiver object
#endif
		TrayWindow*           mTrayWindow;          // active system tray icon
		TQTime                 mStartOfDay;          // start-of-day time currently in use
		TQColor                mPrefsExpiredColour;  // expired alarms text colour
		int                   mPrefsExpiredKeepDays;// how long expired alarms are being kept
		TQValueList<ProcData*> mCommandProcesses;    // currently active command alarm processes
		TQValueList<DcopTQEntry> mDcopQueue;          // DCOP command queue
		int                   mPendingQuitCode;     // exit code for a pending quit
		bool                  mPendingQuit;         // quit once the DCOP command and shell command queues have been processed
		bool                  mProcessingQueue;     // a mDcopQueue entry is currently being processed
		bool                  mHaveSystemTray;      // whether there is a system tray
		bool                  mNoSystemTray;        // no KDE system tray exists
		bool                  mSavedNoSystemTray;   // mNoSystemTray before mCheckingSystemTray was true
		bool                  mCheckingSystemTray;  // the existence of the system tray is being checked
		bool                  mSessionClosingDown;  // session manager is closing the application
		bool                  mOldRunInSystemTray;  // running continuously in system tray was selected
		bool                  mDisableAlarmsIfStopped; // disable alarms whenever KAlarm is not running
		bool                  mRefreshExpiredAlarms; // need to refresh the expired alarms display
		bool                  mSpeechEnabled;       // speech synthesis is enabled (kttsd exists)
		bool                  mKOrganizerEnabled;   // KOrganizer options are enabled (korganizer exists)
};

inline KAlarmApp* theApp()  { return KAlarmApp::getInstance(); }

#endif // KALARMAPP_H