#ifndef KADU_PROTOCOL_H
#define KADU_PROTOCOL_H

#include <qobject.h>
#include <qstring.h>
#include <qdatetime.h>

#ifdef __sun__
#include <sys/types.h>
#endif /* __sun__ */

#include "status.h"
#include "usergroup.h"

typedef uint32_t UinType;

class Protocol : public QObject
{
	Q_OBJECT

	private:
		UserStatus &writeableStatus() { return *NextStatus; }
		friend class Kadu;

	protected:
		QDateTime ConnectionTime;

		QString ProtocolID;
		QString id;

		/**
			Bieżący status. Zmieniany po połączeniu, oraz w przypadku zmiany statusu kiedy połączenie
			jest już zainicjowane.

			@see login
			@see connected
			@see NextStatus
			@see UserStatus
			@see status
		**/
		UserStatus *CurrentStatus;

		/**
			Następny status. Ustalany zewnętrznie przy wykorzystaniu metody status i odpowiednich
			slotów klasy UserStatus. Zmiana wywołuje jedną z metod iWantGo... i w konsekwencji zmianę
			statusu (w razie konieczności też zalogowanie).

			@see login
			@see connected
			@see CurrentStatus
			@see UserStatus
			@see status
		**/
		UserStatus *NextStatus;

	public:
		Protocol(const QString &proto, const QString &id, QObject *parent = 0, const char *name = 0);
		virtual ~Protocol();

		/**
			Status użytkownika. Za pomocą tej metody możemy go zmienić, pobrać ikonę statusu i wykonać
			kilka innych ciekawych rzeczy.

			1. Zmiana statusu:
			<code>
				Protocol *proto;

				...

				proto->status().setOnline("Jestem zalogowany"); // zalogowanie i ustawienie opisu
				proto->status().setFriendsOnly(true);           // tryb tylko dla przyjaciół
				...
				proto->status().setOffline();                   // wylogowanie, usunięcie opisu
			</code>

			2. Sprawdzenie statusu:
			<code>
				Protocol *proto;

				if (proto->status().isOnline())                 // jesteśmy online
					...
				else if (proto->status().isInvisible())         // jesteśmy niewidzialni
					...

				// można też:
				switch (proto->status().status())
				{
					case Online:
						break;
					case Busy:
						break;
					case Invisible:
						break;
					case Offline:
						break;
				}
			</code>

			3. Pobranie ikony i nazwy statusu
			<code>
				QPixmap pix;
				QString name;
				Protocol *proto;

				...

				pix = proto->status().pixmap();
				name = proto->status().name();
			</code>

			@see currentStatus
		**/
		const UserStatus &nextStatus() { return *NextStatus; }

		/**
			Rzeczywisty aktualny status. Można go wykorzystać tylko w trybie do odczytu (pobranie
			ikony, nazwy, sprawdzenie rzeczywistego stanu połączenia).

			@see status
		**/
		const UserStatus &currentStatus() const { return *CurrentStatus; }

		QString protocolID() const { return ProtocolID; }

		QString ID() const { return id; }

		virtual bool validateUserID(QString& uid) = 0;

		virtual UserStatus *newStatus() const = 0;

		const QDateTime &connectionTime() const;

	public slots:
		/**
			Wysyła wiadomość bez formatowania tekstu. Jeśli adresatów jest więcej niż jeden, to wysyłana
			jest wiadomość konferencyjna. Zwracany jest numer sekwencyjny wiadomości, jeśli
			przypadkiem byśmy chcieli śledzić jej potwierdzenie.
			@param users lista użytkowników, do których wysyłamy wiadomość
			@param mesg wiadomość, którą wysyłamy - kodowanie zmieniane wewnątrz
		**/
		virtual QString sendMessage(UserListElements users, const QString &mesg) = 0;
		/**
			Wysyła wiadomość bez formatowania tekstu. Zwracany jest numer sekwencyjny wiadomości, jeśli
			przypadkiem byśmy chcieli śledzić jej potwierdzenie.
			@param users lista użytkowników, do których wysyłamy wiadomość
			@param mesg wiadomość, którą wysyłamy - kodowanie zmieniane wewnątrz
		**/
		QString sendMessage(UserListElement user, const QString &mesg);


	signals:

		/**
			udało się zalogować
		**/
		void connected();

		/**
			rozpoczynamy procedurę logowania się
		**/
		void connecting();

		/**
			rozłączyliśmy się z serwerem
		**/
		void disconnected();

		/**
			wystąpił błąd połączenia
			@param protocol protokół
			@param reason napis do wyświetlenia dla użytkownika
		**/
		void connectionError(Protocol *protocol, const QString &server, const QString &reason);

		/**
			\fn void messageFiltering(const UserGroup *users, QCString& msg, bool& stop)
			Sygnal daje mozliwosc operowania na wiadomosci
			ktora ma byc wyslana do serwera juz w jej docelowej
			formie po konwersji z unicode i innymi zabiegami.
			Tresc wiadomosci mozna zmienic podmieniajac wskaznik
			msg na nowy bufor i zwalniajac stary (za pomoca free).
			Mozna tez przerwac dalsza jej obrobke ustawiajac
			wskaznik stop na true.
			\param users lista użytkowników
			\param msg wiadomość
			\param stop zakończenie dalszej obróbki sygnału
		**/
		void sendMessageFiltering(const UserListElements users, QString &msg, bool &stop);
		/**
			wiadomość nie została dostaczona
		**/
		void messageNotDelivered(const QString &message);
		/**
			wiadomość została przyjęta przez serwer
			TODO: WTF??
		**/
		void messageAccepted();

		/**
			\fn receivedMessageFilter(Protocol *protocol, UserListElements senders, const QString &msg, time_t time, bool &ignore);
			Filtrujemy wiadomość. Można ją odrzucić albo i nie.
			\param protocol protokół na którym otrzymaliśmy wiadomość
			\param senders lista nadawców
			\param message komunikat w postaci Unicode HTML
			\param time czas nadania wiadomości
			\param ignore po ustawieniu na true wiadomość jest ignorowana
		**/
		void receivedMessageFilter(Protocol *protocol, UserListElements senders, const QString &message, time_t time, bool &ignore);
		/**
			\fn messageReceived(Protocol *protocol, UserListElements senders, const QString &msg, time_t time);
			Otrzymaliśmy wiadomość.
			\param protocol protokół na którym otrzymaliśmy wiadomość
			\param senders lista nadawców
			\param message komunikat w postaci Unicode HTML
			\param time czas nadania wiadomości
		**/
		void messageReceived(Protocol *protocol, UserListElements senders, const QString &message, time_t time);

	private:
		Protocol(const Protocol &) {}
		virtual Protocol &operator=(const Protocol &){return *this;}
};

#endif
