#ifndef TRADE_WIDGET_H
#define TRADE_WIDGET_H

#include <QtGui>
#include "ui_TradeWidget.h"
#include "ItemWidget.h"
#include "tradeOfferDialog.h"
#include "tradeItem.h"
#include "softProj\clientServer\structs.h"
#include "softProj\DetailsWidget\SimpleItem.h"
#include "tradeInvitationDialog.h"
#include "softProj\Main\MessageDialog.h"
#include "softProj\Main\ConfirmDialog.h"
#include "commitDialog.h"
#include <deque>
#include "softProj\WeaponsWidget\fightWidgetRowWidget.h"

class TradeWidget;

enum ETradeTableType {
	TRADE_TABLE_OWNED, TRADE_TABLE_OWNED_OFFERS, TRADE_TABLE_ENEMY, TRADE_TABLE_ENEMY_OFFERS
};

enum EFortressTableType {
	FORTRESS_TABLE_OWNED, FORTRESS_TABLE_ENEMY, FORTRESS_TABLE_SECOND_OWNED
};

enum ETradeType {
	TRADE_TRADE_WITH_ENEMY, TRADE_TRADE_WITH_SELF
};

enum ETradeStep {
	TRADE_STEP_SELECT_SELF_FORTRESS, 
	TRADE_STEP_BEFORE_SELECT_PARTNER_FORTRESS, 
	
	TRADE_STEP_BEFORE_SEND_INVITATION, 

	TRADE_STEP_INVITATION_SENT_WAITING_FOR_PARTNER_DECISION,
	TRADE_STEP_INVITATION_DECISION_SENT_WAITING_FOR_SERVER_RESPONSE,

	TRADE_STEP_OFFER_ITEMS, 	

	TRADE_STEP_COMMIT_SENT_WAITING_FOR_PARTNER_DECISION,
	TRADE_STEP_COMMIT_RECEIVED_WAITING_FOR_SELF_DECISION,
	TRADE_STEP_COMMIT_DECISION_SENT_WAITING_FOR_SERVER_RESPONSE,
};

///Displayes items, that can be traded between players. 
class TradeTable : public QWidget {
    Q_OBJECT

public:
    TradeTable(TradeWidget *parent, ETradeTableType tableType, bool onlyScienceIndependent);

    void setTitle(QPushButton *titleLabel); /**< Sets title name of the trade widget. */
    void setTable(QTableWidget *tableWidget);
    void setSearchButton(QPushButton *searchButton); //TODO, FIXME, COMMENTME
    void setShowAllButton(QPushButton *showAllButton); //TODO, FIXME, COMMENTME
    void setSearchEdit(QLineEdit *searchEdit); //TODO, FIXME, COMMENTME

    void clearFilteredContent();
    void clearAllContent();
    void insertItem(TradeItem *row);       
    void connectSignals();

	void addCount(int row, unsigned long long working, unsigned long long damaged);
	void removeCount(int row, unsigned long long working, unsigned long long damaged);

	int findRowOfItem(unsigned long id);
	TradeItem * findItemRow(int row, int col);
	TradeItem * findItemById(unsigned long id);

	void removeRow(int row);
	void removeRowAndItem(TradeItem * item, int row);

	std::map<id_t, TradeItem *>::const_iterator storageBegin();
	std::map<id_t, TradeItem *>::const_iterator storageEnd();
protected:            	
    virtual void cellClicked(TradeItem * item);

    QPushButton *titleLabel_;
    QTableWidget *tableWidget_;
    QPushButton *searchButton_;
    QPushButton *showAllButton_;
    QLineEdit *searchEdit_;

    TradeWidget * tradeWidget_;

    typedef std::map<QString, TradeItem *> ItemsMap;
    typedef std::vector<TradeItem *> ItemsVector;

    int insertItemIntoTable(TradeItem * item);

    std::map<id_t, TradeItem *> rows_;
private slots:
    void cellClickedSlot(int row, int col);
	void itemClickedSlot(const warehouse_item_status & item);	
private slots:
    void searchClickedSlot();
    void showAllClickedSlot();
private:	
	ETradeTableType tableType_;
	bool onlyScienceIndependent_;
};

class FortressTable : public QWidget {
    Q_OBJECT

public:
    FortressTable(TradeWidget *parent, EFortressTableType tableType);

    void setTitle(QPushButton *titleLabel); /**< Sets title name of the trade widget. */
    void setTable(QTableWidget *tableWidget);
    void setSearchButton(QPushButton *searchButton); //TODO, FIXME, COMMENTME
    void setShowAllButton(QPushButton *showAllButton); //TODO, FIXME, COMMENTME
    void setSearchEdit(QLineEdit *searchEdit); //TODO, FIXME, COMMENTME

    void clearFilteredContent();
    void clearAllContent();
    FightWidgetRowWidget * insertItem(FortressItemRow *row);       
    void connectSignals();

	int findRowOfItem(unsigned long id);
	FortressItemRow * findItemRow(int row, int col);
	FortressItemRow * findItemById(unsigned long id);

	void removeRow(int row);
	void removeRowAndItem(FortressItemRow * item, int row);		
	void setRowAsClicked(int row);
	void setNoRowAsClicked();
protected:            	
    virtual void cellClicked(FortressItemRow * item, int row);

    QPushButton *titleLabel_;
    QTableWidget *tableWidget_;
    QPushButton *searchButton_;
    QPushButton *showAllButton_;
    QLineEdit *searchEdit_;

    TradeWidget * tradeWidget_;

    typedef std::map<QString, FortressItemRow *> ItemsMap;
    typedef std::vector<FortressItemRow *> ItemsVector;

    FightWidgetRowWidget * insertItemIntoTable(FortressItemRow * item);

    std::map<long, FortressItemRow *> rows_;

	FightWidgetRowWidget * clickedFortressRow_;	
private slots:
    void cellClickedSlot(int row, int col);
	void itemClickedSlot(id_t itemId);	
private slots:
    void searchClickedSlot();
    void showAllClickedSlot();
private:	
	EFortressTableType tableType_;
};

enum EMovementStateDirection {
	TRADE_MOVEMENT_STATE_DIRECTION_OWNED_OFFER, 
	TRADE_MOVEMENT_STATE_DIRECTION_OWNED_ITEMS,
	TRADE_MOVEMENT_STATE_DIRECTION_PARTNER_OFFER,
	TRADE_MOVEMENT_STATE_DIRECTION_PARTNER_ITEMS,
	TRADE_MOVEMENT_STATE_DIRECTION_NONE,
};

class TradeWidget : public QWidget {
	Q_OBJECT
public:
	TradeWidget(QWidget *parent);
	~TradeWidget();
private:
	Ui::TradeWidget * ui_;

	ETradeType tradeType_;

	TradeTable * ownedItemsTable_;
	TradeTable * ownedOfferTable_;
	TradeTable * enemyOfferTable_;
	TradeTable * enemyItemsTable_;

	FortressTable * ownedFortressesTable_;
	FortressTable * ownedSecondFortressesTable_;
	FortressTable * enemyFortressesTable_;

	TradeOfferDialog * tradeOfferDialog_;
	CommitDialog * commitDialog_;
	MessageDialog * waitForCommitResultDialog_;
	EMovementStateDirection currentState_;
	int selectedRow_;

	void showOfferDialog(TradeItem * item);

	/* ITEMS */
	void clearAllOwnedItems();
	void clearAllGiveItems();
	void clearallGetItems();
	void clearAllEnemyItems();

	void insertOwnedItem(TradeItem * item);
	void insertOwnedOffer(TradeItem * item);
	void insertEnemyOffer(TradeItem * item);
	void insertEnemyItem(TradeItem * item);

	/* FORTRESSES */
	void clearAllOwnedFortresses();
	void clearAllOwnedOppositeFortresses();
	void clearAllEnemyFortresses();

	FightWidgetRowWidget * insertOwnedFortress(FortressItemRow * item);
	FightWidgetRowWidget *  insertSecondOwnedFortress(FortressItemRow * item);
	FightWidgetRowWidget *  insertEnemyFortress(FortressItemRow * item);	

	void setSelfPartner(FortressItemRow * item);
	void setEnemyPartner(FortressItemRow * item);

	void changeState(EMovementStateDirection state);
	bool isInState(EMovementStateDirection state);

	void moveItemTo(TradeTable * targetTable, TradeItem * item);
	TradeItem * moveItemFrom(TradeTable * sourceTable, TradeItem * item, int row, unsigned long offerWorking, unsigned long offerDamaged);

	void setActiveStep(QLabel * stepLabel);

	QString stepSelectOwnedFortress_;
	QString stepSelectSecondOwnedFortress_;
	QString stepAcceptStartAndWaitForStartAcceptance_;
	QString stepWaitForStartAcceptance_;
	QString stepAcceptStart_;
	QString stepCommitTrade_;
	QString stepInvitationSentWaitingForPartnerDecision_;

	QString partnerTradeStep_;
	QString selfTradeStep_;
	
	bool isSynchronizing_;

	void changeStep(ETradeStep step);

	ETradeStep currentStep_;
	std::string tradeRole_;
	ETradingCommitRole commitRole_;

	void startSelfTrade(const trade_invitation_data & invitation, const trade_data & selfTradeData, const trade_data & partnerTradeData);
	void startPartnerTrade(const trade_invitation_data & invitation, const trade_data & data, bool isUserHost);
	void startSpaceTrade(const trade_invitation_data & invitation, const trade_data & selfTradeData);
	void startTradeCommon(const trade_invitation_data & invitation);
	void sendTradeInvitation();

	TradeInvitationDialog* tradeInvitationDialog_;
	MessageDialog* messageDialog_;

	void showTradeInvitationDialog(const trade_invitation_data & invitation);
	void showMessageDialog(const std::wstring & title, const std::wstring & message, const std::string & iconKey);

	void createWaitForAcceptDialog();
	void createTradeInvitationDialog();
	void createMessageDialog();
	void createCommitDialog();

	void signalMoveTradeItem(TradeItem * item, const std::string & tradeDirection, unsigned long long working, unsigned long long damaged);
	void signalCommitTrade();

	std::list<trade_invitation_data> invitations_;
	void rejectAllPreviousInvitations();

	bool matchesSelectedPartners(id_t ownedFortressId, id_t partnerFortressId);
	void removeMatchedInvitations(id_t ownedFortressId, id_t partnerFortressId);

	trade_data partnerResources_;
public:	
	/** Clears client state of the widget */
	void clearState();

	void ownedItemClicked(TradeItem * item);
	void ownedOfferClicked(TradeItem * item);
	void enemyOfferClicked(TradeItem * item);
	void enemyItemClicked(TradeItem * item);
	
	void moveToEnemyItemsFromEnemyOffer(TradeItem * item, int row);
	void moveToEnemyOfferFromEnemyItems(TradeItem * item, int row);
	void moveToOwnedItemsFromOwnedOffer(TradeItem * item, int row);
	void moveToOwnedOfferFromOwnedItems(TradeItem * item, int row);

	void moveFromEnemyItems(TradeItem * item, int itemRow, unsigned long long working, unsigned long long damaged);
	bool moveItemFromTableAndDeleteSplit(const trade_movement_data & tradeData, TradeTable * sourceTable);
	bool moveItemFromTableToTable(id_t itemId, TradeTable * sourceTable, TradeTable * targetTable, unsigned long long working, unsigned long long damaged);
	bool moveItemToTableNoReturn(id_t itemId, TradeTable * targetTable, unsigned long long working, unsigned long long damaged);

	void ownedFortressClicked(FortressItemRow * item, int row);
	void ownedSecondFortressClicked(FortressItemRow * item, int row);
	void enemyFortressClicked(FortressItemRow * item, int row);

	void setOwnedItems(const std::list<warehouse_item_status> & items);
	void setEnemyItems(const std::list<warehouse_item_status> & items);

	void stepPartnerTrade();
	void stepSelfTrade();
	void stepSelectYourFortress(bool reloadData);

	void setOwnedFortresses(const std::vector<SimpleItem> & items);
	void setSecondOwnedFortresses(const std::vector<SimpleItem> & items);
	void setEnemyFortresses(const std::vector<SimpleItem> & items);
	 
	void answerSendTradeInvitation(const trade_invitation_data & invitation, const std::string & reason, const std::string & tradeRole);	
	void answerSendTradeInvitation(const trade_invitation_data & invitation, const trade_data & selfTradeData, const std::string & reason, const std::string & tradeRole);
	void answerSendTradeInvitation(const trade_invitation_data & invitation, const trade_data & selfTradeData, const trade_data & partnerTradeData, const std::string & reason, const std::string & tradeRole);
	void answerSendTradeInvitationFromBuild(const trade_invitation_data & invitation, const trade_data & selfTradeData, const trade_data & partnerTradeData, const std::string & reason, const std::string & tradeRole);
	void answerDecideTradeInvitation(const trade_invitation_data & invitation);
	void answerDecideTradeInvitation(const trade_invitation_data & invitation, const trade_data & tradeData);
	void answerCancelTrade(id_t ownedFortressId, id_t partnerFortressId, const std::string & reason, const std::string & tradeRole);
	void answerMoveTradeItem(const trade_movement_data & tradeData, bool isAuthor);
	void answerMoveTradeResource(const trade_resource_movement_data & tradeData, bool isAuthor);
	void answerCancelTradeCommit(id_t selfFortressId, id_t partnerFortressId, const std::string & reason);
	
	void receiveTradeInvitation(const trade_invitation_data & invitation);
	void receiveTradeInvitationDecision(const trade_invitation_data & invitation);
	void receiveTradeInvitationDecision(const trade_invitation_data & invitation, const trade_data & tradeData);
	void receiveTradeCancelation(id_t ownedFortressId, id_t partnerFortressId);	

	void commitTrade(unsigned long selfFortressId, unsigned long partnerFortressId, ETradingResult result);
	void prepareCommitTrade(unsigned long selfFortressId, unsigned long partnerFortressId, ETradingCommitRole commitRole);

	void signalMoveOwnedTradeResource(game_resource_type resourceType, unsigned long long value);
	void signalMovePartnerTradeResource(game_resource_type resourceType, unsigned long long value);
private slots:
	void submitTradeOfferSlot();
	void cancelTradeOfferSlot();	

	void rejectDialogSlot();

	void submitButtonClickedSlot();
	void cancelButtonClickedSlot();

	//void cancelWaitForAcceptDialogSlot();
	void submitMessageDialogSlot();

	void cancelTradeInvitationDialogSlot();
	void submitTradeInvitationDialogSlot();
	void postponeTradeInvitationDialogSlot();

	void ownedDeuteriumChangedSlot(unsigned long long value);
	void ownedEnergyChangedSlot(unsigned long long value);
	void ownedHeavyWaterChangedSlot(unsigned long long value);
	void ownedIlmeniteChangedSlot(unsigned long long value);
	void ownedPlasmaChangedSlot(unsigned long long value);
	void ownedTitanChangedSlot(unsigned long long value);
	void ownedUlreaChangedSlot(unsigned long long value);
	void ownedCrystalsChangedSlot(unsigned long long value);

	void enemyDeuteriumChangedSlot(unsigned long long value);
	void enemyEnergyChangedSlot(unsigned long long value);
	void enemyHeavyWaterChangedSlot(unsigned long long value);
	void enemyIlmeniteChangedSlot(unsigned long long value);
	void enemyPlasmaChangedSlot(unsigned long long value);
	void enemyTitanChangedSlot(unsigned long long value);
	void enemyUlreaChangedSlot(unsigned long long value);
	void enemyCrystalsChangedSlot(unsigned long long value);	

	void submitCommitInvitationDialogSlot();
	void cancelCommitInvitationDialogSlot();

	void tradeWithSpaceButtonClickedSlot();
signals:
	void inviteTradePartnerSignal(id_t hostFortressId, id_t invitedFortressId);
	void cancelTradeSignal();
	void tradePartnerFortressesSignal(id_t ownedFortressId);
	void decideTradeInvitationSignal(id_t hostFortressId, id_t invitedFortressId, bool accept);
	void startTradeSignal();
	void moveTradeItemSignal(const trade_client_movement_data & data);
	void commitTradeSignal(id_t selfFortressId, id_t partnerFortressId, const client_trade_data & selfOffer, const client_trade_data & partnerOffer);
	void moveTradeResourceSignal(const trade_resource_movement_data & data);
	void cancelTradeCommitSignal(id_t selfFortressId, id_t partnerFortressId);
	void ownedFortressesSignal();

	/** Signals that widget wants to show dialog */
	void showDialogSignal();

	/** Signals that widget wants to hide dialog */
	void hideDialogSignal();
};

#endif