#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 "gadu.h"
#include "notify_slots.h"
#include "userlist.h"

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

			QObject *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, Notifier> notifiers; //nazwa powiadamiacza("Hints") -> obiekt powiadomienia
		QMap<QString, QString> notifySignals; //nazwa sygnału("NewMessage") -> sygnał (SIGNAL(newMessage(...)))
		QStringList eventNames;

		/*
		 * 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);

	private slots:
		/* pomocniczy slot */
		void newChatSlot(UinsList senders, const QString& msg, time_t time);
		/* pomocniczy slot */
		void probablyNewMessage(UinsList senders, const QString& msg, time_t time, bool &);

		/*
		 * łą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"
			"Message" - inna wiadomość
		 *
		 * nie trzeba definiować wszystkich slotów
		 */
		void registerNotifier(const QString &name, QObject *notifier,
							const QMap<QString, QString> &notifierSlots);
		/*
		 * wyrejestrowuje obiekt
		 */
		void unregisterNotifier(const QString &name);

		QStringList notifiersList() const;
	
	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 userStatusChanged(const UserListElement &, const UserStatus &oldStatus, bool onConnection);

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

		/* nowa rozmowa */
		void newChat(const UinsList &senders, const QString& msg, time_t time);

		/* nowa wiadomość w oknie chat */
		void newMessage(const UinsList &senders, const QString& msg, time_t time, bool &grab);

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

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

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

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

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

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

		/* 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
