#ifndef CHAT_WIDGET_H
#define CHAT_WIDGET_H

#include <QtGui>
#include <string>
#include <vector>
#include <map>

#include "softProj\ChatWidget\ChatMessage.h"
#include "softProj\ChatWidget\BuddyHolder.h"
#include "ui_ChatWidget.h"

typedef std::pair<int, ChatBuddy *> TBuddyPair;

/// Represents chat conversation of user with some other buddy. 
/** Represents chat conversation of user with some other buddy. Stores sent messages to
target buddy and also received messages from the same buddy. There is one conversation instance
for each buddy that user can communicate with. It also stores saved input in case user switches 
conversation between buddies, so it can be reloaded later.
*/
class ChatConversation {
public:
	ChatConversation(ChatBuddy * toBuddy);	
	~ChatConversation();

	/** Gets id of target buddy
	@return Id of target buddy
	*/
	int getToBuddyId();

	/** Gets ChatBuddy instance of target buddy
	@return ChatBuddy instance of target buddy
	*/
	ChatBuddy * getToBuddy();

	/** Adds messsage to the list of received messages 
	@param message Received message 
	*/
	void receiveMessage(ChatMessage * message);

	/** Adds messsage to the list of received messages and increases 
	number of unread messages
	@param message Received message 
	*/
	void receiveUnreadMessage(ChatMessage * message);

	/** Saves displayed input from textarea so it could be reloaded later when this
	conversation becomes active again.
	@param input Input to save
	*/
	void saveInput(const std::string * input);

	/** Gets saved input so it coul be displayed again
	@return Saved input
	*/
	std::string loadInput();

	/** Creates new instance of ChatMessage as an outgoing message and adds it to sent messages list. 
	It adds given text to the message and also adds id of target buddy.
	@param message Actual text of message
	@return ChatMessage instance representing sent message
	*/
	ChatMessage * sendMessage(const std::string * message);

	/** Gets list of received messages in this conversation
	@return List of received messages 
	*/
	std::vector<ChatMessage *> & getReceivedMessages();

	/** Gets list of all messages, received and sent in this conversation
	@return List of all messages 
	*/
	std::vector<ChatMessage *> & getMessages();

	/** Gets count of unread messages
	@return Count of unread messages
	*/
	int getUnreadMessagesCount();

	/** Marks all messages as read, so sets number of unread messages to zero */
	void readAllMessages();	


private:
	ChatBuddy * toBuddy_;

	std::vector<ChatMessage *> receivedMessages_;
	std::vector<ChatMessage *> sendedMessages_;
	std::vector<ChatMessage *> messages_;
	int messagesSend_;
	int unreadMessagesCount_;
	std::string savedInput_;
};

typedef std::pair<int, ChatConversation *> TConversationPair;

///Widget where you can chat with other players.
/** Widget where you can chat with other players. It contains table with buddies list that user can
chat with and conversation window, that is displayed sent and received messages and input box for new messages. 
*/
class ChatWidget : public QWidget
{
	Q_OBJECT
public:
	ChatWidget(QWidget * parent);
	~ChatWidget();

	/** Shows chat widget */
	void showChat();

	/** Hides chat widget */
	void hideChat();

	/** Receives chat message and adds it to the current conversation and displays it
	@param message Received message
	*/
	void receiveMessage(ChatMessage * message);

	/** Switches conversation and sets new conversation related to given buddy id
	@param id Id of target buddy that will be target for new conversation 
	*/
	void switchConversation(int id);

	/** Switches conversation and sets new conversation related to given buddy 
	@param id Target buddy that will be target for new conversation 
	*/
	void switchConversation(ChatBuddy * buddy);

	/** Adds new buddy to the list of buddies and creates conversation related to him
	@param buddy New buddy 
	*/
	void addBuddy(ChatBuddy * buddy);

	/** Sets all buddies that user can conversate with from given list of buddies
	@param buddies List of buddies that user can conversate with
	*/
	void setBuddies(std::vector<ChatBuddy *> buddies);

	/** Removes all buddies from the list */
	void clearBuddies();

	/** Sets name of the user displayed in conversation */
	void setMyName(const std::string & name);	

	/** Clears client state of the widget */
	void clearState();
public slots:
	/** Slot for signal that user want to send new message that he wrote to writing box */
	void confirmMessageSlot();

	/** Slot for signal that user changed buddy in table with buddies and want to switch conversation
	@param row Row number in a table of buddies
	@param col Column number in a table of buddies
	*/
	void changeBuddySlot(int row, int column);
signals:
	/** Signals that message is ready to be sent
	@param message Instance of message to be sent
	*/
	void sendChatMessageSignal(ChatMessage * message);

	/** Signals that received message does not belong to current conversation and so
	it was received as an unread messages until user switch to related conversation. It 
	is useful, because listener can display number of unread messages.
	@param message Message that was received
	*/
	void unreadChatMessageSignal(ChatMessage * message);

	/** Signals that user read given number of messages. It is useful, because listener
	can adjust number of unread messages 
	@param count Number of messages that were read
	*/
	void readChatMessagesSignal(int count);
private:
	Ui::ChatWidget ui_;
	bool writingEnabled_;
	bool isChatVisible_;
	std::string myName_;

	void displayMessage(ChatMessage * message);
	std::string * formatMessage(ChatMessage * message);	
	
	std::map<int, ChatConversation *> conversations_;
	std::map<int, BuddyHolder *> buddyWidgets_;
	std::map<int, ChatBuddy *> buddies_;

	ChatBuddy * getCurrentToBuddy();
	ChatConversation * currentConversation_;
	
	void enableWriting();
	void disableWriting();
	void sendMessage(const std::string * message);
	const std::string * retriveMessageFromInput();
	
	/** Receives message as unread, when user is not displaying the widget
	@param message Received message
	@param shouldEmit If widget should emit signal that it received unread message
	*/
	void receiveUnreadMessage(ChatMessage *  message, bool shouldEmit);

	void clearConversationOutput();
	void clearConversationInput();
	void displayConversation(ChatConversation * conversation);
	void addBuddyWidget(ChatBuddy * buddy);	
	void addConversation(ChatBuddy * buddy);
	void saveConversationInput(ChatConversation * conversation);
	void loadConversationInput(ChatConversation * conversation);

	void activateBuddyWidget(ChatBuddy * toBuddy);
	void deactivateBuddyWidget(ChatBuddy * toBuddy);

	BuddyHolder * findBuddyWidget(int buddyId);
	ChatConversation * findConversation(int buddyId);
	ChatBuddy * findBuddy(int buddyId);

	void addMessageFromUnknownBuddy(ChatMessage * message);
	std::list<ChatMessage *> unreadMessages_;
};

#endif
