#ifndef KADU_CHAT_MANAGER_H
#define KADU_CHAT_MANAGER_H

#include <qobject.h>
#include <qtimer.h>

#include "chat_widget.h"
#include "chat_window.h"
#include "chat_message.h"
#include "configuration_aware_object.h"
#include "toolbar.h"
#include "usergroup.h"

class Protocol;

/**
	Klasa pozwalająca zarządzać otwartymi oknami rozmów: otwierać,
	zamykac, szukać okna ze wględu na listę użytkowników itp.
	\class ChatManager
	\brief Klasa zarządzająca oknami ChatWidget
**/

class ChatManager : public QObject, ConfigurationAwareObject
{
	Q_OBJECT

	private:
		ChatList ChatWidgets; /*!< lista okien*/
		QValueList<UserListElements> ClosedChatUsers; /*!< użytkownicy, których okna zostały zamknięte*/

		/**
			\struct ChatInfo
			Struktura przechowuje informacje o danym oknie
		**/
		struct ChatInfo
		{
			UserListElements users;/*!< lista użytkowników
					identyfikująca okno */
			QMap<QString, QVariant> map; /*!< parametry
							danego okna */
			ChatInfo() : users(), map() {}
		};
		QValueList<ChatInfo> addons; /*!< lista parametrów okien */
		QTimer refreshTitlesTimer;

	private slots:

		void autoSendActionActivated(const UserGroup* users, const QWidget* source, bool is_on);
		void clearActionActivated(const UserGroup* users);
		void boldActionActivated(const UserGroup* users, const QWidget* source, bool is_on);
		void italicActionActivated(const UserGroup* users, const QWidget* source, bool is_on);
		void underlineActionActivated(const UserGroup* users, const QWidget* source, bool is_on);
		void colorActionActivated(const UserGroup* users, const QWidget* source);
		void insertEmoticonActionActivated(const UserGroup* users, const QWidget* source);
		void insertEmoticonActionAddedToToolbar(const UserGroup*, ToolButton* button, ToolBar* toolbar);
		void whoisActionActivated(const UserGroup* users);
		void ignoreUserActionActivated(const UserGroup* users);
		void blockUserActionActivated(const UserGroup* users);
		void insertImageActionActivated(const UserGroup* users);
		void sendActionActivated(const UserGroup* users);
		void chatActionActivated(const UserGroup* users);

	protected:
		virtual void configurationUpdated();

	public:
		/**
			\fn ChatManager(QObject* parent=NULL, const char* name=NULL)
			Konstruktor tworzący obiekt zarządzający oknami
			\param parent rodzic okna
			\param name nazwa obiektu
		**/
		ChatManager(QObject* parent=NULL, const char* name=NULL);

		/**
			\fn ~ChatManager()
			Destruktor zamyka wszystkie otwarte okna
		**/
		~ChatManager();

		/**
			\fn static void initModule()
			Rejestruje opcje modulu Chat w oknie konfiguracji
		**/
		static void initModule();

		/**
			\fn static void closeModule()
			Wyrejestrowuje opcje modułu z okna konfiguracji
		**/
		static void closeModule();

		/**
			\fn const ChatList& chats() const
			Funkcja zwraca listę otwartych okien Chat
		**/
		const ChatList& chats() const;

		/**
			\fn QValueList<UserListElements> closedChatsUsers() const
			Funkcja zwraca listę użytkowników, dla których zamknięto okna Chat
		**/
		const QValueList<UserListElements> closedChatUsers() const;

		/**
			\fn ChatWidget* findChatWidget(const UserGroup *group) const;
			Funkcja zwraca wskaźnik do okna z listą
			użytkowników group
			\param group lista użytkowników
			\return wskaźnik do okna jeśli istnieje w przeciwnym
			 wypadku zwraca NULL
		**/
		ChatWidget* findChatWidget(const UserGroup *group) const;

		/**
			\fn Chat* findChat(UserListElements users) const;
			Funkcja zwraca wskaźnik do okna z listą
			użytkowników group
			\param users lista użytkowników
			\return wskaźnik do okna jeśli istnieje w przeciwnym
			 wypadku zwraca NULL
		**/
		ChatWidget* findChatWidget(UserListElements users) const;

		// co za głupota
		// TODO: przenieść do klasy ChatWidget / ewentualnie do nowo-utworzonej klasy Chat
		/**
			\fn QVariant& getChatWidgetProperty(const UserGroup *group, const QString &name)
			Funkcja zwraca wartość własności "name" okna
			określonego przez group
			\param group grupa użytkowników identyfikująca okno
			\param name nazwa własności
			\return zwraca wartość własności jeśli określone okno
			istnieje,\n jeśli nie to tworzy taką
			własność (ustawia na pustą)
		**/
		QVariant& getChatWidgetProperty(const UserGroup *group, const QString &name);

		void loadOpenedWindows();
		void saveOpenedWindows();

	public slots:

		/**
			\fn int openChatWidget(QString initialProtocol, UserListElements users, time_t time = 0)
			Funkcja otwiera nowe okno Chat z wymienionymi rozmowcami.
			\param initialProtocol protokół początkowy
			\param users lista użytkowników identyfikujących okno
			\param time time of pending message that created a chat or 0 if not applicable
			\return zwracany jest numer otwartego okna
		**/
		int openChatWidget(Protocol *initialProtocol, const UserListElements &users, bool forceActivate = false);

		/**
			\fn void openPendingMsgs(UserListElements users)
			Funkcja wpisuje zakolejkowane wiadomości do okna
			z użytkownikami "users"
			\param users lista użytkowników identyfikujących okno
		**/
		void openPendingMsgs(UserListElements users, bool forceActivate = false);

		/**
			\fn void openPendingMsgs()
			Funkcja wpisuje wszystkie zakolejkowane wiadomości
			do odpowiednich okien
		**/
		void openPendingMsgs(bool forceActivate = false);

		/**
			\fn void deletePendingMsgs(UserListElements users)
			Funkcja usuwa zakolejkowane wiadomości
			z użytkownikami "users"
			\param users lista użytkowników identyfikujących okno
		**/
		void deletePendingMsgs(UserListElements users);


		//TODO: opisac funkcje sendMessage(..)
		/*
			Niebardzo rozumiem tej funkcji (czemu jest uin i uins)
		*/
		void sendMessage(UserListElement user, UserListElements selected_users);

		/**
			\fn void closeAllWindows()
			Funkcja zamyka wszystkie okna chat
		**/
		void closeAllWindows();

		/**
			\fn int registerChatWidget(ChatWidget* chat)
			Dodaje okno do menadżera
			\param chat wskaźnik do okna ktore chcemy dodać
			\return zwraca numer naszego okna po zarejestrowaniu
		**/
		int registerChatWidget(ChatWidget* chat);

		/**
			\fn void unregisterChat(Chat* chat)
			Funkcja wyrejestrowuje okno z managera \n
			Zapisuje własności okna \n
			wysyła sygnał chatDestroying i chatDestroyed
			\param chat okno które będzie wyrejestrowane
		**/
		void unregisterChatWidget(ChatWidget* chat);

		/**
			\fn void refreshTitles()
			Funkcja odświeża tytuły wszystkich okien
		**/
		void refreshTitles();
		void refreshTitlesLater();

		/**
			\fn void refreshTitlesForUser(UserListElement user)
			Funkcja odświeża tytuły okien które zawierają uin
			\param user użytkownik, którego
			opis/status będzie odświeżany
		**/
		void refreshTitlesForUser(UserListElement user);

		/**
			\fn void setChatWidgetProperty(const UserGroup *group, const QString &name, const QVariant &value)
			Funkcja pozwala przypisać określonemu czatowi
			(nawet jeżeli on jeszcze nie istnieje) pewne własności
			\param group grupa użytkowników identyfikujących okno
			\param name nazwa własności
			\param value wartość własności
		**/
		void setChatWidgetProperty(const UserGroup *group, const QString &name, const QVariant &value);

	signals:

		/**
			\fn void handleNewChatWidget(ChatWidget *chat, bool &handled)
		 	Sygnał ten jest wysyłany po utworzeniu nowego okna chat.
			Jeśli zmienna handled zostanie ustawiona na true, to 
			niezostanie utworzony nowy obiekt ChatWindiw
			\param chat nowe okno chat
		**/
		void handleNewChatWidget(ChatWidget *chat, bool &handled);
		/**
			\fn void chatWidgetCreated(ChatWidget *chat)
		 	Sygnał ten jest wysyłany po utworzeniu nowego okna chat
			\param chat nowe okno chat
		**/
		void chatWidgetCreated(ChatWidget *chat);

		void chatWidgetActivated(ChatWidget *);

		/**
			\fn void chatCreated(const UserGroup *group)
		 	Sygnał ten jest wysyłany po utworzeniu nowego okna chat
			\param chat nowe okno chat
			\param time time of pending message that created a chat or 0 if not applicable
		**/
		void chatWidgetCreated(ChatWidget *chat, time_t time);

		/**
			\fn void chatDestroying(const UserGroup *group)
		 	Sygnał ten jest wysyłany przed zamnknięciem okna chat
			\param chat zamykane okno
		**/
		void chatWidgetDestroying(ChatWidget *chat);

		/**
			\fn void chatOpen(UserListElements users)
			Sygnał ten jest wysyłaniy podczas każdej próby
			otwarcia nowego okna chat nawet jeśli już taki istnieje
			\param chat otwarte okno
		**/
		void chatWidgetOpen(ChatWidget *chat);

		void chatWidgetTitlesUpdated();

		/**
			\fn void messageSentAndConfirmed(UserListElements receivers, const QString& message)
			This signal is emited when message was sent
			and it was confirmed.
			When confirmations are turned off signal is
			emited immediately after message was send.
			\param receivers list of receivers
			\param message the message
		**/
		void messageSentAndConfirmed(UserListElements receivers, const QString& message);
};

/**
	wskaźnik do obiektu ChatManager'a
**/
extern ChatManager* chat_manager;

#endif
