#ifndef KADU_GROUPS_MANAGER_H
#define KADU_GROUPS_MANAGER_H

#include <qmap.h>
#include <qobject.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtimer.h>
#include <qvariant.h>
#include <qwmatrix.h>

#include "configuration_aware_object.h"
#include "usergroup.h"
#include "userlistelement.h"

class KaduTabBar;

/**
	Klasa służąca przede wszystkim zarządzaniu nazwanymi grupami kontaktów,
	ale także zarządza grupami typu: blokowani, blokujący, tylko z opisami, tylko dostępni, anonimowi
	\class GroupsManager
	\brief
**/
class GroupsManager : public QObject, ConfigurationAwareObject
{
	Q_OBJECT

	GroupsManager();
	~GroupsManager();
	QMap<QString, UserGroup *> Groups;
	KaduTabBar *GroupBar;
	int lastId;
	QString currentGroup;
	bool showBlocked;
	bool showBlocking;
	bool showOffline;
	bool showWithoutDescription;
	bool showOnlineAndDescription;
	QTimer refreshTimer;

private slots:
	void userDataChanged(UserListElement elem, QString name, QVariant oldValue, QVariant currentValue, bool massively, bool last);
	void userAddedToMainUserlist(UserListElement elem, bool massively, bool last);
	void userRemovedFromMainUserlist(UserListElement elem, bool massively, bool last);

	void userAdded(UserListElement elem, bool massively, bool last);
	void userRemoved(UserListElement elem, bool massively, bool last);

	void tabSelected(int id);
	void iconThemeChanged();

protected:
	virtual void configurationUpdated();

public:
	/**
		\fn static void initModule()
		inicjuje moduł zarządcy grup
	**/
	static void initModule();

	/**
		\fn static void closeModule()
		sprząta po module zarządcy grup
	**/
	static void closeModule();

	/**
		\fn UserGroup *group(const QString &name) const
		zwraca grupę kontaktów o nazwie name
		\param name nazwa grupy
		\return grupa kontaktów
	**/
	UserGroup *group(const QString &name) const;

	/**
		\fn UserGroup *addGroup(const QString &name)
		dodaje nową grupę kontaktów o nazwie name
		\param name nazwa grupy
		\return grupa kontaktów
	**/
	UserGroup *addGroup(const QString &name);

	/**
		\fn void removeGroup(const QString &name)
		usuwa grupę kontaktów o nazwie name
		\param name nazwa grupy
	**/
	void removeGroup(const QString &name);

	/**
		\fn void setTabBar(KaduTabBar *bar)
		ustawia pas zakładek, na którym klasa będzie operować oraz inicjuje
		wewnętrzne dane klasy
		\param bar pas zakładek, w którym będę umieszczane zakładki grup
	**/
	void setTabBar(KaduTabBar *bar);

	/**
		\fn QStringList groups() const
		\return lista grup
	**/
	QStringList groups() const;

	/**
		\fn bool groupExists(const QString &name)
		\param name nazwa grupy
		\return informacja czy grupa istnieje
	**/
	bool groupExists(const QString &name);

	/**
		\fn QString currentGroupName() const
		\return nazwa aktualnie wybranej grupy
	**/
	QString currentGroupName() const;

	/**
		\fn void setIconForTab(const QString &name, bool showIcon)
		ustawia lub usuwa ikonkę dla grupy o nazwie name
		\param name nazwa grupy
	**/
	void setIconForTab(const QString &name);

public slots:

	/**
		\fn void setActiveGroup(const QString &name)
		ustawia aktywną grupę na name
		\param name nazwa grupy
	**/
	void setActiveGroup(const QString& group);

	/**
		\fn void refreshTabBar()
		odświeża pasek zakładek grup
	**/
	void refreshTabBar();

	/**
		\fn void refreshTabBarLater()
		odświeża pasek zakładek grup, ale po zakończeniu bieżacych operacji
	**/
	inline void refreshTabBarLater() { refreshTimer.start(0, true); }

	/**
		\fn void changeDisplayingBlocking()
		włącza lub wyłącza wyświetlanie kontaktów blokujących
		w głównej liście kontaktów w zależności od poprzedniego stanu
	**/
	void changeDisplayingBlocking();

	/**
		\fn void changeDisplayingBlocked()
		włącza lub wyłącza wyświetlanie kontaktów blokowanych
		w głównej liście kontaktów w zależności od poprzedniego stanu
	**/
	void changeDisplayingBlocked();

	/**
		\fn void changeDisplayingOffline()
		włącza lub wyłącza wyświetlanie kontaktów niedostępnych
		w głównej liście kontaktów w zależności od poprzedniego stanu
	**/
	void changeDisplayingOffline();

	/**
		\fn void changeDisplayingWithoutDescription()
		włącza lub wyłącza wyświetlanie kontaktów o statusach bez opisu
		w głównej liście kontaktów w zależności od poprzedniego stanu
	**/
	void changeDisplayingWithoutDescription();

	/**
		\fn void changeDisplayingOnlineAndDescription()
		włącza lub wyłącza wyświetlanie kontatków o statusach "dostępny"
		lub "zajęty" oraz kontatków z opisem
	**/
	void changeDisplayingOnlineAndDescription();

};

extern GroupsManager *groups_manager;

/**
	\class UsersWithDescription
	Klasa grupująca kontakty o statusie z opisem,
	automatycznie synchronizująca się z główną listą kontaktów
**/
class UsersWithDescription : public UserGroup
{
	Q_OBJECT
	public:
		UsersWithDescription();
		virtual ~UsersWithDescription();
	private slots:
		void statusChangedSlot(UserListElement elem, QString protocolName,
							const UserStatus &oldStatus, bool massively, bool last);
};
extern UsersWithDescription *usersWithDescription;

/**
	\class OnlineUsers
	Klasa grupująca kontakty o statusie "dostępny" lub "zajęty",
	automatycznie synchronizująca się z główną listą kontaktów
**/
class OnlineUsers : public UserGroup
{
	Q_OBJECT
	public:
		OnlineUsers();
		virtual ~OnlineUsers();
	private slots:
		void statusChangedSlot(UserListElement elem, QString protocolName,
							const UserStatus &oldStatus, bool massively, bool last);
};
extern OnlineUsers *onlineUsers;

/**
	\class OnlineAndDescriptionUsers
	Klasa grupująca kontakty o statusie "dostępny",
	lub "zajęty", oraz kontakty mająca opis. Klasa
	automatycznie synchronizuje się z główną listą kontaktów
**/
class OnlineAndDescriptionUsers : public UserGroup
{
	Q_OBJECT

	public:
		OnlineAndDescriptionUsers();
		virtual ~OnlineAndDescriptionUsers();

	private slots:
		void statusChangedSlot(UserListElement elem, QString protocolName,
					    const UserStatus &oldStatus, bool massively, bool last);
		void userChangedSlot(UserListElement elem, bool massively, bool last);
		void protocolAddedOrRemoved(UserListElement elem, QString protocolName, bool massively, bool last);
};
extern OnlineAndDescriptionUsers *onlineAndDescriptionUsers;

/**
	\class OfflineUsers
	Klasa grupująca kontakty o statusie "niedostępny",
	automatycznie synchronizująca się z główną listą kontaktów
**/
class OfflineUsers : public UserGroup
{
	Q_OBJECT
	public:
		OfflineUsers();
		virtual ~OfflineUsers();
	private slots:
		void statusChangedSlot(UserListElement elem, QString protocolName,
					    const UserStatus &oldStatus, bool massively, bool last);
		void userChangedSlot(UserListElement elem, bool massively, bool last);
		void protocolAddedOrRemoved(UserListElement elem, QString protocolName, bool massively, bool last);
};
extern OfflineUsers *offlineUsers;

/**
	\class BlockedUsers
	Klasa grupująca kontakty, które są blokowane,
	automatycznie synchronizująca się z główną listą kontaktów
**/
class BlockedUsers : public UserGroup
{
	Q_OBJECT
	public:
		BlockedUsers();
		virtual ~BlockedUsers();
	private slots:
		void protocolUserDataChangedSlot(QString protocolName, UserListElement elem,
							QString name, QVariant oldValue, QVariant currentValue,
							bool massively, bool last);
};
extern BlockedUsers *blockedUsers;

/**
	\class BlockingUsers
	Klasa grupująca kontakty o statusie blokującym,
	automatycznie synchronizująca się z główną listą kontaktów
**/
class BlockingUsers : public UserGroup
{
	Q_OBJECT
	public:
		BlockingUsers();
		virtual ~BlockingUsers();
	private slots:
		void statusChangedSlot(UserListElement elem, QString protocolName,
							const UserStatus &oldStatus, bool massively, bool last);
};
extern BlockingUsers *blockingUsers;

/**
	\class AnonymousUsers
	Klasa grupująca kontakty anonimowe,
	automatycznie synchronizująca się z główną listą kontaktów
**/
class AnonymousUsers : public UserGroup
{
	Q_OBJECT
	public:
		AnonymousUsers();
		virtual ~AnonymousUsers();
	private slots:
		void userDataChangedSlot(UserListElement elem,
							QString name, QVariant oldValue, QVariant currentValue,
							bool massively, bool last);
		void userAdded(UserListElement elem, bool massively, bool last);
		void removingUser(UserListElement elem, bool massively, bool last);
};
extern AnonymousUsers *anonymousUsers;

/**
	\class AnonymousUsersWithoutMessages
	Klasa grupująca kontakty anonimowe, nie mające wiadomości do odebrania
	automatycznie synchronizująca się z główną listą kontaktów
**/
class AnonymousUsersWithoutMessages : public UserGroup
{
	Q_OBJECT
	public:
		AnonymousUsersWithoutMessages();
		virtual ~AnonymousUsersWithoutMessages();
	private slots:
		void messageFromUserAdded(UserListElement elem);
		void messageFromUserDeleted(UserListElement elem);

		void userDataChangedSlot(UserListElement elem,
							QString name, QVariant oldValue, QVariant currentValue,
							bool massively, bool last);
		void userAdded(UserListElement elem, bool massively, bool last);
		void removingUser(UserListElement elem, bool massively, bool last);
};
extern AnonymousUsersWithoutMessages *anonymousUsersWithoutMessages;

#endif
