#ifndef NOTIFY_H
#define NOTIFY_H

#include <qgroupbox.h>
#include <qmap.h>
#include <qobject.h>
#include <qpair.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qvaluelist.h>
#include <qvariant.h>

#include <time.h>

#include "main_configuration_window.h"
#include "notification.h"
#include "protocol.h"
#include "userlist.h"

class MessageNotification;

class QListBox;

/**
 * @defgroup notify Notify
 * @{
 */

/**
	@enum CallbackRequirement
	Określa, czy dane zdarzenie wymaga podjęcia od użytkownika akcji innej niż domyślne zaakceptowanie/odrzucenie.
 **/
enum CallbackRequirement {
	CallbackRequired,
	CallbackNotRequired
};

/**
	@enum CallbackCapacity
	Określa, czy dany notifikator potrafi obsłużyć zdarzenia wymagajace od użytkownika akcji innej niż domyślne zaakceptowanie/odrzucenie.
 **/
enum CallbackCapacity {
	CallbackSupported,
	CallbackNotSupported
};

/**
	@class NotifierConfigurationWidget
	@author Vogel
	@short Widget konfiguracyjny dla Notifiera.

	Widget jest tworzony i dodawany w odpowiednim miejscu w oknie konfiguracyjnym.
	Zawartość elementów zmienia się po wyborze innej notyfikacji w oknie konfiguracyjnym.
	Wiget zapamietuje wszystkie zmiany dla wszystkich typów notyfikacji i w odpowienim
	momencie je zapisuje.
**/
class NotifierConfigurationWidget : public QWidget
{
	Q_OBJECT

public:
	NotifierConfigurationWidget(QWidget *parent = 0, char *name = 0) : QWidget(parent, name) {}

	/**
		W tej metodzie widget może wczytać konfigruacje wszystkich zdarzeń.
	 **/
	virtual void loadNotifyConfigurations() = 0;
	/**
		W tej metodzie widget musi zapisać wszystkie zmienione konfiguracje
		wszystkich zmienionych zdarzeń.
	 **/
	virtual void saveNotifyConfigurations() = 0;

public slots:
	/**
		Slot wywoływany, gdy widget ma przełączyć się na konfigruację innego zdarzenia.
		Zmiany w aktualnym zdarzeniu powinny zostać zapisane.

		@arg event - nazwa nowego zdarzenia
	 **/
	virtual void switchToEvent(const QString &event) = 0;

};

/**
	@class Notifier
	@brief Klasa abstrakcyjna opisująca notifikator.

	Notifykatory zajmują się wyświetlaniem lub informowaniem w inny sposób użytkownika o występujących
	w programie zdarzeniach (nowa rozmowa, nowy transfer pliku, błąd...).

	Notyfikatory mogę umożliwiać użytkownikowi podjęcie akcji jak odebranie lub zignorownie rozmowy,
	odebranie pliku, kontynuacje odbierania pliku i inne. Niektóry notifikatory nie będą
	implementować akcji, dlatego też niektóre zdarzenia nie mogą być przez nie obsługiwane.
 **/
class Notifier : public virtual QObject
{
	public:
		Notifier(QObject *parent = 0, const char *name = 0) : QObject(parent, name) {};
		virtual ~Notifier() {};

		/**
			Określa, czy notifikator poradzi sobie ze zdarzeniami wymagajacymi podjęcia akcji.
		 **/
		virtual CallbackCapacity callbackCapacity() { return CallbackNotSupported; }

		/**
			Metoda informująca notifikator o nowym zdarzeniu. Zdarzenie może wywołać
			sygnał closed(), po którym notyfikator musi przestać informować użytkownika
			o danym zdarzeniu (na przykład, musi zamknąć skojarzone ze zdarzeniem okno).
		 **/
		virtual void notify(Notification *notification) = 0;

		/**
			Kopiuje konfiguracje jednego zdarzenia do drugiego.
			Używane przy przejściu z 0.5 na 0.6 - po 0.6 zostanie usunięte.
		 **/
		virtual void copyConfiguration(const QString &fromEvent, const QString &toEvent) = 0;

		/**
			Zwraca widget, jaki zostanie dodany do okna konfiguracyjnego
			na prawo od odpowiedniego CheckBoxa.
			Może zwrócić zero.
		 **/
		virtual NotifierConfigurationWidget *createConfigurationWidget(QWidget *parent = 0, char *name = 0) = 0;
};

class NotifyGroupBox : public QGroupBox
{
	Q_OBJECT

	QString Notificator;

private slots:
	void toggledSlot(bool toggled);

public:
	NotifyGroupBox(const QString &notificator, const QString &caption, QWidget *parent = 0, char *name = 0);
	virtual ~NotifyGroupBox() {}

	QString notificator() { return Notificator; }

signals:
	void toggled(const QString &notificator, bool toggled);

};

class Notify : public ConfigurationUiHandler
{
	Q_OBJECT

	QListBox *allUsers;
	QListBox *notifiedUsers;
	ConfigComboBox *notifications;
	ConfigGroupBox *notificationsGroupBox;

	struct NotifierData
	{
		Notifier *notifier;
		NotifierConfigurationWidget *configurationWidget;
		NotifyGroupBox *configurationGroupBox;
		QMap<QString, bool> events;
	};

	QMap<QString, NotifierData> Notifiers; //nazwa powiadamiacza("Hints") -> obiekt powiadomienia

	struct NotifyEvent
	{
		QString name;
		CallbackRequirement callbackRequirement;
		const char *description;
		NotifyEvent() : name(), callbackRequirement(CallbackNotRequired), description(0){}
	};
	QValueList<NotifyEvent> NotifyEvents;

	QString CurrentEvent;

	void import_connection_from_0_5_0(const QString &notifierName, const QString &oldConnectionName, const QString &newConnectionName);
	void createDefaultConfiguration();

	void addConfigurationWidget(NotifierData &notifier, const QString &name);
	void removeConfigurationWidget(NotifierData &notifier);

private slots:

	void messageReceived(Protocol *protocol, UserListElements senders, const QString &msg, time_t t);

	void connectionError(Protocol *protocol, const QString &server, const QString &message);
	void statusChanged(UserListElement elem, QString protocolName, const UserStatus &oldStatus, bool massively, bool last);

	void moveToNotifyList();
	void moveToAllList();

	void configurationWindowApplied();
	void eventSwitched(int index);
	void notifierToggled(const QString &notifier, bool toggled);

	void mainConfigurationWindowDestroyed();

public:
	Notify(QObject *parent=0, const char *name=0);
	virtual ~Notify();

	virtual void mainConfigurationWindowCreated(MainConfigurationWindow *mainConfigurationWindow);

	void notify(Notification *notification);

	void registerNotifier(const QString &name, Notifier *notifier);
	void unregisterNotifier(const QString &name);

	void registerEvent(const QString &name, const char *description, CallbackRequirement callbackRequirement);
	void unregisterEvent(const QString &name);

	QStringList notifiersList() const;
	const QValueList<Notify::NotifyEvent> &notifyEvents();

};

extern Notify *notification_manager;

/** @} */

#endif
