#ifndef KADU_USERLISTELEMENT_H
#define KADU_USERLISTELEMENT_H

#include <qhostaddress.h>
#include <qobject.h>
#include <qstring.h>
#include <qvariant.h>

#include "status.h"

class ULEPrivate;
class UserGroup;

typedef long int UserListKey;

/**
	Typ opisujący stan powiadamiania.
	\enum NotifyType
	\brief Typ opisujący stan powiadamiania.
**/
enum NotifyType {
	NotifyGlobal = 0, /*!< powiadomienia zależne od globalnych ustawień */
	NotifyOff = 1, /*!< powiadomienia wyłączone */
	NotifyOwn = 2 /*!< indywidualne ustawienie powiadamiania */
};

/**
	Klasa reprezentująca kontakt (użytkownika na liście kontaktów).
	\class UserListElement
	\brief Klasa reprezentująca kontakt.
	Ze zwględu na silną hermetyzację, należy unikać dawania dostępu przez wskaźniki / referencje
	(nawet const) na zewnątrz do wewnętrznych danych.

	Klasa została zbudowana w taki sposób, że przekazywanie przez wartość jest
	bardzo tanie (żadne pola nie są kopiowane). Jednocześnie nie można wykonać
	niezależnej (nie powiązanej ze źródłem) kopii obiektu, gdyż mogłoby to
	doprowadzić do stworzenia kilku kontaktów o tych samych danych (czego należy
	się wystrzegać!).
**/
class UserListElement : public QObject
{
	Q_OBJECT
	public:
		/**
			\fn UserListElement()
		**/
		UserListElement();

		/**
			\fn UserListElement(const UserListElement &copyMe)
			Konstruktor kopiujący.
		**/
		UserListElement(const UserListElement &copyMe);

		/**
			\fn virtual ~UserListElement()
			Zwalnia pamięć związaną z kontaktem, gdy licznik odwołań == 1
		**/
		virtual ~UserListElement();

		/**
			\fn void operator = (const UserListElement &copyMe)
			Operator kopiujący. Dane będą dzielone.
			\param copyMe obiekt klasy UserListElement który będzie skopiowany.
		**/
		UserListElement &operator = (const UserListElement &copyMe);

		inline bool operator==(const UserListElement &u) const {	return key() == u.key();	}

		inline bool operator!=(const UserListElement &u) const {	return key() != u.key();	}

		inline bool operator<(const UserListElement &u) const  {	return key()  < u.key();	}

		/**
			\fn QString ID(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca identyfikator kontaktu we wskazanym protokole.
		**/
		QString ID(const QString &protocolName) const;

		/**
			\fn const UserStatus &status(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca status kontaktu w protokole protocolName.
		**/
		const UserStatus &status(const QString &protocolName) const;

		/**
			\fn QVariant data(const QString &name) const
			\param name nazwa własności
			Zwraca własność (która nie jest związana z żadnym protokołem)
		**/
		QVariant data(const QString &name) const;

		/**
			\fn QVariant protocolData(const QString &protocolName, const QString &name) const
			\param protocolName identyfikator protokołu
			\param name nazwa właśności
			Zwraca własność name dla protokołu protocolName.
		**/
		QVariant protocolData(const QString &protocolName, const QString &name) const;

		/**
			\fn QStringList protocolList() const
			Zwraca listę identyfikatorów protokołów dla danego kontaktu.
		**/
		QStringList protocolList() const;

		/**
			\fn QStringList protocolDataKeys(const QString &protocolName) const
			Zwraca listę identyfikatorów pól dla protokołu protocolName.
		**/
		QStringList protocolDataKeys(const QString &protocolName) const;

		/**
			\fn QStringList nonProtocolDataKeys() const
			Zwraca listę identyfikatorów pól nie związanych z żadnym protokołem.
		**/
		QStringList nonProtocolDataKeys() const;

		/**
			\fn QString firstName() const
			Zwraca imię kontaktu.
		**/
		QString firstName() const;

		/**
			\fn QString lastName() const
			Zwraca nazwisko kontaktu.
		**/
		QString lastName() const;

		/**
			\fn QString nickName() const
			Zwraca pseudonim kontaktu.
		**/
		QString nickName() const;

		/**
			\fn QString altNick() const
			Zwraca wyświetlany pseudonim kontaktu.
		**/
		QString altNick() const;

		/**
			\fn QString mobile() const
			Zwraca numer telefonu kontaktu.
		**/
		QString mobile() const;

		/**
			\fn QString email() const
			Zwraca adres E-Mail kontaktu.
		**/
		QString email() const;

		/**
			\fn QString homePhone() const
			Zwraca numer telefonu domowego kontaktu.
		**/
		QString homePhone() const;

		/**
			\fn QString aliveSound(NotifyType &type) const
			Zwraca sposób powiadamiania dźwiękiem o zmianach statusu kontaktu.
		**/
		QString aliveSound(NotifyType &type) const;

		/**
			\fn QString messageSound(NotifyType &type) const
			Zwraca sposób powiadamiania dźwiękiem o wiadomościach od kontaktu.
		**/
		QString messageSound(NotifyType &type) const;

		/**
			\fn bool isAnonymous() const
			Zwraca informację, czy kontakt jest anonimowy czy nie.
		**/
		bool isAnonymous() const;

		/**
			\fn bool notify() const
			Zwraca informację, czy użytkownik jest powiadamiany o kontakcie czy nie.
		**/
		bool notify() const;

		/**
			\fn bool usesProtocol(const QString &name) const
			\param name identyfikator protokołu
			Zwraca informację o tym czy do kontaktu przypisany jest protokół o wskazanym identyfikatorze.
		**/
		bool usesProtocol(const QString &name) const;

		/**
			\fn bool hasIPAddress(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca informację czy znany jest adres IP we wskazanym protokole.
		**/
		bool hasIP(const QString &protocolName) const;

		/**
			\fn QHostAddress IP(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca adres IP kontaktu.
		**/
		QHostAddress IP(const QString &protocolName) const;

		/**
			\fn QString DNSName(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca nazwę domeny kontaktu (jeśli znaleziona).
		**/
		QString DNSName(const QString &protocolName) const;

		/**
			\fn short port(const QString &protocolName) const
			\param protocolName identyfikator protokołu
			Zwraca numer portu kontaktu.
		**/
		short port(const QString &protocolName) const;

	public slots:
		/**
			\fn QVariant setData(const QString &name, const QVariant &val, bool massively = false, bool last = false)
			ustawia własność kontaktu stowarzyszoną z nazwą "name"
			zwraca starą wartość
			\param name nazwa własności
			\param val nowa wartość
			\param massively true, gdy jest to część większych zmian
			\param last true, gdy massively == true i jest to ostatnia zmiana

			pola bezprotokołowe:

				QStringList Groups;
				QString FirstName; Imię kontaktu.
				QString LastName; Nazwisko kontaktu.
				QString NickName; Pseudonim kontaktu.
				QString AltNick; Pseudonim kontaktu, który jest wyświetlany na liście.
				QString Mobile; Numer telefonu kontaktu.
				QString Email; E-Mail kontaktu.
				bool Anonymous; Informuje, czy kontakt jest anonimowy czy nie.
				bool Notify; Informuje czy mamy włączone powiadamianie o kontakcie.

				NotifyType AliveSound; Przechowuje informację o sposobie powiadamiania
										o zmianie statusu kontaku dźwiękiem.
				QString OwnAliveSound; Jeśli sposób powiadamiania o zmianie statusu kontaktu ma wartość OWN,
									to ta zmienna przechowuje nazwę pliku dźwiękowego do odtworzenia.

				NotifyType MessageSound; Przechowuje informację o sposobie powiadamiania
										o nowej wiadomości od kontaktu dźwiękiem.
				QString OwnMessageSound;  Jeśli sposób powiadamiania o nowej wiadomości od kontaktu ma wartość OWN,
										to ta zmienna przechowuje nazwę pliku dźwiękowego do odtworzenia.

				QString HomePhone; Numer telefonu domowego kontaktu.
		**/
		QVariant setData(const QString &name, const QVariant &val, bool massively = false, bool last = false);

		/**
			\fn QVariant setProtocolData(const QString &protocolName, const QString &name, const QVariant &val, bool massively = false, bool last = false)
			\param protocolName identyfikator protokołu
			\param name nazwa własności
			\param val nowa wartość
			\param massively true, gdy jest to część większych zmian
			\param last true, gdy massively == true i jest to ostatnia zmiana
			\return stara wartość
			Ustawia własność name związaną z protokołem protocolName na val.

			dla protokołu "Gadu" dostępne są następujące pola:

				int MaxImageSize; Maksymalny rozmiar obrazka, jaką może przyjąć kontakt.
				QHostAddress IP; Adres IP kontaktu (jeśli wykryty).
				QString DNSName; Nazwa domenu kontaktu (jeśli znaleziona).
				short Port; Port kontaktu (jeśli wykryty).
				int Version; Wersja protokołu używanego przez kontakt.
				bool Blocking; Informuje czy blokujemy kontakt, czy nie.
				bool OfflineTo; Informuje czy mamy włączony tryb "niedostępny dla kontaktu" dla tego kontaktu.
		**/
		QVariant setProtocolData(const QString &protocolName, const QString &name, const QVariant &val, bool massively = false, bool last = false);

		/**
			\fn void addProtocol(const QString &protocolName, const QString &id, bool massively = false, bool last = false)
			\param protocolName identyfikator protokołu
			\param id identyfikator w tym protokole w postaci napisu
			\param massively true, gdy jest to część większych zmian
			\param last true, gdy massively == true i jest to ostatnia zmiana
			Dodaje do kontaktu informację o używanym protokole.
		**/
		void addProtocol(const QString &protocolName, const QString &id, bool massively = false, bool last = false);

		/**
			\fn void deleteProtocol(const QString &protocolName, bool massively = false, bool last = false)
			\param protocolName identyfikator protokołu
			\param massively true, gdy jest to część większych zmian
			\param last true, gdy massively == true i jest to ostatnia zmiana
			Usuwa informacje o protokole.
		**/
		void deleteProtocol(const QString &protocolName, bool massively = false, bool last = false);

		/**
			\fn void setStatus(const QString &protocolName, const UserStatus &status, bool massively = false, bool last = false)
			\param protocolName identyfikator protokołu
			\param status nowy status
			\param massively true, gdy jest to część większych zmian
			\param last true, gdy massively == true i jest to ostatnia zmiana
			Zmienia status kontaktu w protokolej protocolName.
		**/
		void setStatus(const QString &protocolName, const UserStatus &status, bool massively = false, bool last = false);

		/**
			\fn void setFirstName(const QString &firstName)
			Ustawia imię dla kontaktu.
			\param firstName imię, które zostanie przydzielone kontaktowi.
		**/
		void setFirstName(const QString &firstName);

		/**
			\fn void setLastName(const QString &lastName)
			Ustawia nazwisko dla kontaktu.
			\param lastName nazwisko, które zostanie przydzielone kontaktowi.
		**/
		void setLastName(const QString &lastName);

		/**
			\fn void setNickName(const QString &nickName)
			Ustawia pseudonim dla kontaktu.
			\param nickName pseudonim, który zostanie przydzielony kontaktowi.
		**/
		void setNickName(const QString &nickName);

		/**
			\fn void setAltNick(const QString &altNick)
			Ustawia wyświetlany pseudonim dla kontaktu.
			\param altNick wyświetlany pseudonim, który zostanie przydzielony kontaktowi.
		**/
		void setAltNick(const QString &altNick);

		/**
			\fn void setMobile(const QString &mobile)
			Ustawia numer telefonu dla kontaktu.
			\param mobile numer telefonu, który zostanie przydzielony kontaktowi.
		**/
		void setMobile(const QString &mobile);

		/**
			\fn void setEmail(const QString &email)
			Ustawia adres E-Mail dla kontaktu.
			\param email adres, który zostanie przydzielony kontaktowi.
		**/
		void setEmail(const QString &email);

		/**
			\fn void setAnonymous(const bool anonymous)
			Ustawia stan anonimowości kontaktu.
			\param anonymous wartość logiczna informująca, że kontakt jest anonimowy, lub nie.
		**/
		void setAnonymous(const bool &anonymous);

		/**
			\fn void setNotify(const bool notify)
			Ustawia stan powiadamiania o kontakcie.
			\param notify wartość logiczna informująca, czy użytkownik ma być powiadamiany o kontakcie.
		**/
		void setNotify(const bool &notify);

		/**
			\fn void setHomePhone(const QString &phone)
			Ustawia numer telefonu domowego dla kontaktu.
			\param phone numer telefonu, który zostanie przydzielony kontaktowi.
		**/
		void setHomePhone(const QString &phone);

		/**
			\fn void setAliveSound(NotifyType type, const QString &file = QString::null)
			Ustawia sposób powiadamiania dźwiękiem o zmianie statusu przez kontakt.
			\param type sposób powiadamiania.
			\arg \c GLOBAL powiadomienia zależne od globalnych ustawień.
			\arg \c OFF powiadomienia wyłączone.
			\arg \c OWN indywidualne ustawienie powiadamiania/

			\param file plik dźwiękowy, wymagany dla indywidualnego ustawienia powiadomień.
		**/
		void setAliveSound(NotifyType type, const QString &file = QString::null);

		/**
			\fn void setMessageSound(NotifyType type, const QString &file = QString::null)
			Ustawia sposób powiadamiania dźwiękiem o nowej wiadomości od kontaktu.
			\param type sposób powiadamiania.
			\arg \c GLOBAL powiadomienia zależne od globalnych ustawień.
			\arg \c OFF powiadomienia wyłączone.
			\arg \c OWN indywidualne ustawienie powiadamiania/

			\param file plik dźwiękowy, wymagany dla indywidualnego ustawienia powiadomień.
		**/
		void setMessageSound(NotifyType type, const QString &file = QString::null);

		/**
			\fn void setAddressAndPort(const QString &protocolName, const QHostAddress &ip, short port)
			\param protocolName identyfikator protokołu
			\param ip adres IP
			\param port port
			Ustawia adres IP i port dla wskazanego protokołu.
		**/
		void setAddressAndPort(const QString &protocolName, const QHostAddress &ip, short port);

		/**
			\fn void setDNSName(const QString &protocolName, const QString &dnsname)
			\param protocolName identyfikator protokołu
			\param dnsname nowa domena
			Ustawia domenę dla wskazanego protokołu.
		**/
		void setDNSName(const QString &protocolName, const QString &dnsname);

		/**
			\fn void refreshDNSName(const QString &protocolName)
			\param protocolName identyfikator protokołu
			Wywołuje zapytanie o nazwę domeny dla kontaktu oraz wypełnia odpowiednie pole kontaktu,
			gdy domena zostanie odnaleziona.
		**/
		void refreshDNSName(const QString &protocolName);

	protected:
		/**
			\fn UserListKey key() const
			Zwraca klucz po którym jest identyfikowany kontakt
		**/
		UserListKey key() const;

	private:
		ULEPrivate *privateData;
		static unsigned long int used;
		friend class UserGroup;
};

#endif
