#ifndef NOTIFY_H
#define NOTIFY_H
#include <qobject.h>
#include <qstring.h>
#include <qmap.h>
#include <qvariant.h>
#include <qpair.h>
#include <qvaluelist.h>
#include <qstringlist.h>

#include <time.h>

#include "notify_slots.h"
#include "protocol.h"
#include "userlist.h"

/**
 * @defgroup notify Notify
 * @{
 */
class Notifier : public QObject {
	public:
		Notifier(QObject *parent = 0, const char *name = 0) : QObject(parent, name) {};
		virtual ~Notifier() {};
		virtual void externalEvent(const QString &notifyType, const QString &msg, const UserListElements &ules) = 0;
};

class Notify : public QObject
{
	Q_OBJECT
	private:
		class NotifierSlots
		{
			public:
			NotifierSlots();
			NotifierSlots(Notifier *notifier, const QMap<QString, QString> &notifierSlots);

			Notifier *notifier; //obiekt "nasłuchujący" na zdarzenia
			QMap<QString, QPair<QString, bool> > notifierSlots; //nazwa sygnału("NewMessage") -> para<slot (SLOT(mójSlotMessage)), czy połączony>
		};
		QMap<QString, NotifierSlots> notifiers; //nazwa powiadamiacza("Hints") -> obiekt powiadomienia
		QMap<QString, QString> notifySignals; //nazwa sygnału("NewMessage") -> sygnał (SIGNAL(newMessage(...)))
		QStringList eventNames;

		class NotifyEvent
		{
			public:
				QString name;
				QCString wname;
				const char *description;
				NotifyEvent() : name(), wname(), description(0){}
		};
		QValueList<NotifyEvent> notifyEvents;
		QMap<QString, QValueList<QCString> > strs;

		/*
		 * dodaje kolumnę checkboksów w konfiguracji,
		 * na podstawie notifierSlots decyduje czy dodać checkboksa aktywnego czy nie
		 */
		void addConfigColumn(const QString &name, const QMap<QString, QString> &notifierSlots);

		/* usuwa kolumnę checkboksów z konfiguracji */
		void removeConfigColumn(const QString &name, const QMap<QString, QPair<QString, bool> > &notifierSlots);

		void addConfigRow(const QString &name, const char *description);
		void removeConfigRow(const QString &name);

	private slots:
		/* pomocniczy slot */
		void newChatSlot(Protocol *protocol, UserListElements senders, const QString &msg, time_t t);
		/* pomocniczy slot */
		void probablyNewMessage(Protocol *protocol, UserListElements senders, const QString &msg, time_t t, bool &grab);

		/*
		 * łączy odpowiedni sygnał z notifierName (np.: Window, Hint, Sound)
		 * ze slotem slotName (np.: NewChat, ConnError)
		 */
		void connectSlot(const QString &notifierName, const QString &slotName);

		/*
		 * rozłącza odpowiedni sygnał z notifierName (np.: Window, Hint, Sound)
		 * od slotu slotName (np.: NewChat, ConnError)
		 */
		void disconnectSlot(const QString &notifierName, const QString &slotName);

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

		/*
		 * rejestruje obiekt, który chce otrzymywać informacje o zdarzeniach
		 * name będzie użyte w oknie konfiguracji (należy podawać angielską nazwę)
		 * slots to mapa odwzorująca nazwy sygnałów na sloty w obiekcie notifier
		 * nazwy sygnałów:
			"NewChat" - nowa rozmowa
			"NewMessage" - nowa wiadomość
			"ConnError" - błąd połączenia
			"StatusChanged" - zmiana statusu ogólna
			"toAvailable" - użytkownik zmienił status na "Dostępny"
			"toBusy" - użytkownik zmienił status na "Zaraz wracam"
			"toInvisible" - użytkownik zmienił status na "Ukryty"
			"toNotAvailable" - użytkownik zmienił status na "Niewidoczny lub Niedostępny"
			"UserBoxChangeToolTip"
			"Message" - inna wiadomość
		 *
		 * nie trzeba definiować wszystkich slotów
		 */
		void registerNotifier(const QString &name, Notifier *notifier,
							const QMap<QString, QString> &notifierSlots);
		/*
		 * wyrejestrowuje obiekt
		 */
		void unregisterNotifier(const QString &name);

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

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

	public slots:
		/*
		 * aktualizuje wszystkie połączenia
		 * wywoływany po zmianie konfiguracji dotyczącej obsługi
		 */
		void updateConnections();

		/*
		 * emituje sygnał message
		 *  jeżeli to==QString::null, to wysyła do wszystkich, którzy są zaznaczeni w konfiguracji
		 *  jeżeli to!=QString::null, to wysyła tylko do jednego
		 * Notifier decyduje, których argumentów użyć
		 */
		void emitMessage(const QString &from, const QString &to, const QString &message=QString(), const QMap<QString, QVariant> *parameters=NULL, const UserListElement *ule=NULL);

		/* obsługa zmian statusów */
		void statusChanged(UserListElement elem, QString protocolName,
							const UserStatus &oldStatus, bool massively, bool last);

		void notify(const QString &notifyType, const QString &msg, const UserListElements &ules = UserListElements());

	signals:
	//UWAGA: razem ze zmianami nazw/parametrów tych sygnałów należy aktualizować wpisy w konstruktorze Notify

		/* nowa rozmowa */
		void newChat(Protocol *protocol, UserListElements senders, const QString &msg, time_t t);

		/* nowa wiadomość w oknie chat */
		void newMessage(Protocol *protocol, UserListElements senders, const QString &msg, time_t t, bool &grab);

		/* błąd połączenia */
		void connectionError(Protocol *protocol, const QString &message);

		/* użytkownik zmienił status */
		void userStatusChanged(UserListElement elem, QString protocolName, const UserStatus &oldStatus);

		/* użytkownik zmienił status na "Dostępny" */
		void userChangedStatusToAvailable(const QString &protocolName, UserListElement);

		/* użytkownik zmienił status na "Zaraz wracam" */
		void userChangedStatusToBusy(const QString &protocolName, UserListElement);

		/* użytkownik zmienił status na "Niewidoczny" */
		void userChangedStatusToInvisible(const QString &protocolName, UserListElement);

		/* użytkownik zmienił status na "Niewidoczny" lub "Niedostępny" */
		void userChangedStatusToNotAvailable(const QString &protocolName, UserListElement);

		void userBoxChangeToolTip(const QPoint &point, UserListElement, bool show);

		/* inna informacja do powiadomienia */
		void message(const QString &from, const QString &msg, const QMap<QString, QVariant> *parameters, const UserListElement *ule);

	signals:
		/* do użytku wewnętrznego */
		void privateMessage(const QString &from, const QString &message, const QMap<QString, QVariant> *parameters, const UserListElement *ule);
};

extern Notify *notify;
extern NotifySlots *notify_slots;

/** @} */

#endif
