#ifndef KADU_CHAT_WIDGET_H
#define KADU_CHAT_WIDGET_H

#include <qdatetime.h>
#include <qwidget.h>
#include <qhbox.h>


#include <qvaluelist.h>

#include "chat_messages_view.h"
#include "config_file.h"
#include "configuration_aware_object.h"
#include "custom_input.h"
#include "emoticons.h"
#include "protocol.h"
#include "usergroup.h"
#include "toolbar.h"

class QAccel;
class QHBox;
class QMimeSourceFactory;
class QObject;
class QPushButton;

class ChatWidget;
class ChatManager;
class ChatMessage;
class ColorSelector;
class EmoticonSelector;
class KaduSplitter;
class KaduTextBrowser;
class UserBox;

/** \typedef QValueList<ChatWidget*> ChatList */
typedef QValueList<ChatWidget*> ChatList;

/**
	Klasa tworząca okno rozmowy, rejestrująca przyciski,
	formatująca wiadomość itp.
	\class ChatWidget
	\brief Okno rozmowy
**/

class ChatWidget : public QHBox, ConfigurationAwareObject
{
	Q_OBJECT

private:
	friend class ChatManager;

	QString Caption; /*!< tytuł okna */
	Protocol *CurrentProtocol;
	UserGroup *Users; /*!< lista użytkowników w danym oknie */
	int index;	/*!< nr okna (z chat menadżera) */
	QColor actcolor; /*!< zmienna przechowująca aktualny kolor */
	QPixmap pix;
	CustomInput* Edit; /*!< okno do wpisywania wiadomości */
	QMimeSourceFactory *bodyformat; /*!< zmienna ustawiająca format */
	EmoticonSelector* emoticon_selector; /*!< okienko do wyboru emotikonek */
	ColorSelector* color_selector; /*!< okienko do wyboru koloru */
	bool AutoSend; /*!< określa czy Return powoduje wysłanie wiadomości */
	bool WaitingForACK;
	UserBox* userbox; /*!< lista kontaktów przydatna gdy jesteśmy w konferencji */
	QString myLastMessage; /*!< zmienna przechowująca naszą ostatnią wiadomość */
	KaduSplitter *vertSplit, *horizSplit; /*!< obiekty oddzielające kontrolki od siebie */

	QDateTime lastMsgTime; /*!< czas ostatniej wiadomości */

	ChatMessagesView* body; /*!< historia rozmowy, proszę NIE dawać dostępu na zewnątrz do tej zmiennej */

	// TODO: remove
	int activationCount;

	unsigned int NewMessagesCount; /*!< liczba nowych wiadomości w oknie rozmowy */

private slots:
	/**
		\fn void changeColor()
		Slot zmieniający kolor czcionki
	**/
	void changeColor(const QWidget* activating_widget);

	/**
		\fn void connectAcknowledgeSlots()
		Slot podłączający potwierdzenie dostarczenia wiadomości
	**/
	void connectAcknowledgeSlots();

	/**
		\fn void disconnectAcknowledgeSlots()
		Slot odłączający potwierdzenie dostarczenia wiadomości
	**/
	void disconnectAcknowledgeSlots();

	void selectedUsersNeeded(const UserGroup*& user_group);

	void sendActionAddedToToolbar(ToolButton*, ToolBar*);

	/**
		\fn void colorActionForceRefresh()
		Slot jest wywoływany, po dodaniu do paska narzędzi akcji zmieniającej
		kolor wiadomości lub zmianie zestawu ikon. Używa setActColor() wymuszając
		odświeżenie koloru na przycisku.
	**/
	void colorActionForceRefresh();

	/**
		\fn void setActColor()
		\param force wymuszenie zmiany
		Ustawia poprawny kolor na przycisku akcji obsługującej kolor wiadomości
	**/
	void setActColor(bool force);

	void keyPressedSlot(QKeyEvent *e, CustomInput *sender, bool &handled);

protected:
	virtual void keyPressEvent(QKeyEvent* e);
	bool keyPressEventHandled(QKeyEvent *);

	virtual void configurationUpdated();

public:
	/**
		Konstruktor okna rozmowy
		\fn Chat(UserListElements usrs, QWidget* parent = 0, const char* name = 0)
		\param usrs lista kontaktów, z którymi prowadzona jest rozmowa
		\param parent rodzic okna
		\param name nazwa obiektu
	**/
	ChatWidget(Protocol *initialProtocol, const UserListElements &usrs, QWidget* parent = 0, const char* name = 0);

	/**
		\fn ~Chat()
		Destruktor okna rozmowy
	**/
	~ChatWidget();

	/**
		Dodaje nową wiadomosć systemową do okna.

		@param rawContent treść wiadomości w postaci HTML
		@param backgroundColor kolor tła wiadomości (format HTML)
		@param fontColor kolor wiadomości (format HTML)
	 **/
	void appendSystemMessage(const QString &rawContent, const QString &backgroundColor, const QString &fontColor);

	/**
		\fn void newMessage(const QString &protocolName, UserListElements senders, const QString &msg, time_t time)
		Dodaje wiadomość do okna
		\param protocolName nazwa protokołu
		\param senders lista użytkowników
		\param msg wiadomośc
		\param time czas
		**/
	void newMessage(const QString &protocolName, UserListElements senders, const QString &msg, time_t time);

	/**
		\fn const UserGroup *users() const
		Zwraca listę numerów rozmowców.
	**/
	const UserGroup *users() const;

	/**
		\fn void repaintMessages()
		Odświeża zawartość okna uwzględniając ewentualne
		zmiany dokonane w którejś wiadomości z listy
		uzyskanej za pomocą metody chatMessages(),
		dodanie nowych wiadomości lub usunięcie istniejących.
	**/
	void repaintMessages();

	/**
		\fn const QString& title() const
		Zwraca aktualny tytuł okna
	**/
	const QString& caption() const;

	/**
		\fn CustonInput* edit()
		Zwraca wskaźnik do okna wpisywania wiadomości
	**/
	CustomInput* edit();

	/**
		\fn bool autoSend() const
		Zwraca wartość określającą, czy Return powoduje
		wysłanie wiadomości.
	**/
	bool autoSend() const;

	bool waitingForACK() const;

	virtual void dragEnterEvent(QDragEnterEvent *e);
	virtual void dropEvent(QDropEvent *e);
	virtual void dragMoveEvent(QDragMoveEvent *e);

	virtual bool eventFilter(QObject *watched, QEvent *e);

	Protocol *currentProtocol();

	unsigned int newMessagesCount() const;

	QDateTime getLastMsgTime();
	QPixmap icon();

	void storeGeometry();
	void restoreGeometry();

	unsigned int countMessages() { return body->countMessages(); }

public slots:
	/**
		\fn void refreshTitle()
		Slot ustawiający tytuł okna zgodnie z konfiguracją
	**/
	void refreshTitle();

	/**
		\fn void addEmoticon(QString)
		Slot dodaje ikonke do pola wpisywania wiadomości
		\param emot ikonka np. <lol>
	**/
	void addEmoticon(QString);

	void messageNotDeliveredSlot(const QString &message);

	void messageAcceptedSlot();

	/**
		\fn void editTextChanged()
		Slot jest wywoływany, gdy zmieniła się zawartość
		pola edycji wiadomości. Ustawia poprawny stan przycisku
		akcji sendAction w oknie rozmowy.
	**/
	void editTextChanged();

	/**
		\fn void appendMessages(const QValueList<ChatMessage *> &)
		Slot dodaj wiadomości do okna
		\param messages lista wiadomości
	**/
	void appendMessages(const QValueList<ChatMessage *> &, bool pending = false);

	/**
		\fn void appendMessage(ChatMessage *)
		Slot dodaj wiadomość do okna
		\param messages lista wiadomości
	**/
	void appendMessage(ChatMessage *, bool pending = false);

	/**
		\fn void sendMessage()
		Slot wywoływany po naciśnięciu przycisku
		do wysyłania wiadomości
	**/
	void sendMessage();

	/**
		\fn void cancelMessage()
		Slot wywoływany po naciśnieciu przycisku anulowania
		wysyłaniu wiadomości
	**/
	void cancelMessage();

	/**
		\fn void writeMyMessage()
		Slot wpisujący wiadomość do okna
		\see sendMessage
	**/
	void writeMyMessage();

	/**
		\fn void curPosChanged(int para, int pos)
		Slot wywoływany kiedy pozycja kursosa zmieniła się
		\param  para nie obslugiwane
		\param pos nie obslugiwane
	**/
	void curPosChanged(int para, int pos);

	/**
		\fn void specialKeyPressed(int key)
		Slot zostaje wywołany gdy naciśnięto specjalny klawisz (skrót)
		odpowiadający np KEY_BOLD
		\param key wartość naciśniętego specjalnego klawisza
	**/
	void specialKeyPressed(int key);

	/**
		\fn void colorChanged(const QColor& color)
		Slot zostaje wywołwany gdy użytkownik zmienił kolor czcionki
		którą będzie pisał
		\param color wartość zmienionego koloru
	**/
	void colorChanged(const QColor& color);

	/**
		\fn void colorSelectorAboutToClose()
		Slot zostaje wywołany przy zamykaniu okna wyboru ikonek
	**/
	void colorSelectorAboutToClose();

	/**
		\fn void clearChatWindow()
		Slot czyszczący okno rozmowy
	**/
	void clearChatWindow();

	/**
		\fn void setAutoSend(bool auto_send)
		Ustaw autowysylanie
	**/
	void setAutoSend(bool auto_send);

	/**
		\fn void emoticonSelectorClicked()
		Slot wyświetlający okno z wyborem emotikonek
	**/
	void openEmoticonSelector(const QWidget* activating_widget);

	/**
		\fn void insertImage()
		Slot wklejający obrazek do okna rozmowy (wybór obrazka)
	**/
	void insertImage();

	void makeActive();
	void markAllMessagesRead();

	void leaveConference();

signals:
	/**
		\fn void messageSendRequested(ChatWidget* chat)
		Sygnal jest emitowany gdy uzytkownik wyda polecenie
		wyslania wiadomosci, np klikajac na guzik "wyslij".
		\param chat wskaźnik do okna które emituje sygnał
	**/
	void messageSendRequested(ChatWidget* chat);

	/**
		\fn void messageSent(ChatWidget* chat)
		Sygnal jest emitowany gdy zakonczy sie proces
		wysylania wiadomosci i zwiazanych z tym czynnosci.
		Oczywiscie nie wiemy czy wiadomosc dotarla.
		\param chat wskaźnik do okna rozmowy,
		 które emitowało sygnał
	**/
	void messageSent(ChatWidget* chat);

	/**
		\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
		just like messageSent() signal.
		\param receivers list of receivers
		\param message the message
	**/
	void messageSentAndConfirmed(UserListElements receivers, const QString& message);

	/**
		\fn void fileDropped(const UserGroup *users, const QString& fileName)
		Sygnał jest emitowany, gdy w oknie Chat
		upuszczono plik.
	\param users lista użytkowników
		\param fileName nazwa pliku
	**/
	void fileDropped(const UserGroup *users, const QString &fileName);

	void messageReceived(ChatWidget *);

	void captionUpdated();
	void closed();

	void keyPressed(QKeyEvent *e, ChatWidget *sender, bool &handled);

};

/**
	@class ChatContainer
	@brief Klasa abstrakcyjna opisująca rodzica klasy ChatWidget.

	Klasa abstrakcyjna z której powinny dziedziczyć klasy będące rodzicami obiektów 
	klasy ChatWidget.
	
	Informuje który chat powinien zostać zamknięty w przypadku np. ignorowania kontaktu 
	z którym prowadzona jest rozmowa
**/

class ChatContainer
{
	public:
		ChatContainer() {};
		virtual ~ChatContainer() {};

		/**
			Metoda informująca, który chat powinien zostać zamknięty
		 **/
		virtual void closeChatWidget(ChatWidget *chat) = 0;
};

#endif
