#ifndef KADU_CHAT_MANAGER_H
#define KADU_CHAT_MANAGER_H

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

#include "chat.h"
#include "chat_message.h"
#include "toolbar.h"
#include "usergroup.h"

class ChatManagerSlots;
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 Chat
**/

class ChatManager : public QObject
{
	Q_OBJECT

	private:
		ChatList Chats; /*!< lista okien*/

		static ChatManagerSlots *chatslots;

		/**
			\fn int openPendingMsg(int index, ChatMessage &msg)
			Funkcja otwierająca zakolejkowaną wiadomość
			\param index nr wiadomości z kolejki
			\param msg wiadomość z kolejki
			\return zwracany jest nr okna w którym została otwarta wiadomość
		**/
		int openPendingMsg(int index, ChatMessage &msg);

		/**
			\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 scrollLockActionActivated(const UserGroup* users, const QWidget* source, bool is_on);
		void clearActionActivated(const UserGroup* users);
		void historyActionActivated(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);

	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 Chat* findChat(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
		**/
		Chat* findChat(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
		**/
		Chat* findChat(UserListElements users) const;

		/**
			\fn QVariant& getChatProperty(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& getChatProperty(const UserGroup *group, const QString &name);

	public slots:

		/**
			\fn void chatMsgReceived(const QString &protocolName, UserListElements senders, const QString& msg, time_t time, bool& grab)
			Slot informujący o odebraniu wiadomości
			\param protocolName nazwa protokołu
			\param senders lista użytkowników identyfikujących okno
			\param msg treść otrzymanej wiadomości
			\param time czas otrzymania wiadomości
			\param grab
		**/
		void chatMsgReceived(Protocol *protocol, UserListElements senders, const QString& msg, time_t time, bool& grab);

		/**
			\fn int openChat(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 parametr sluzy do sprawdzenia ile wiadomosci
			z historii ma sie pojawic w oknie.
			\return zwracany jest numer otwartego okna
		**/
		int openChat(QString initialProtocol, UserListElements users, time_t time = 0);

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

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

		/**
			\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 registerChat(Chat* chat)
			Dodaje okno do menadżera
			\param chat wskaźnik do okna ktore chcemy dodać
			\return zwraca numer naszego okna po zarejestrowaniu
		**/
		int registerChat(Chat* 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 unregisterChat(Chat* 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 changeAppearance()
			Funkcja odświeża kolory i czcionki we wszystkich oknach
		**/
		void changeAppearance();

		/**
			\fn void setChatProperty(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 setChatProperty(const UserGroup *group, const QString &name, const QVariant &value);

	signals:

		/**
			\fn void chatCreated(const UserGroup *group)
		 	Sygnał ten jest wysyłany po utworzeniu nowego okna chat
			\param group lista użytkowników, z którymi tworzymy nowy chat
		**/
		void chatCreated(const UserGroup *group);

		/**
			\fn void chatDestroying(const UserGroup *group)
		 	Sygnał ten jest wysyłany przed zamnknięciem okna chat
			\param group lista użytkownikówów, którzy występują w tym chacie
		**/
		void chatDestroying(const UserGroup *group);

		/**
			\fn void chatDestroyed(const UserGroup *group)
		 	Sygnał ten jest wysyłany po zamnknięciem okna chat
			\param group lista użytkowników, którzy
			występowały w tym chacie
		**/
		void chatDestroyed(const UserGroup *group);

		/**
			\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 users lista użytkowników
		**/
		void chatOpen(UserListElements users);

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