#ifndef QT_SCIENCE_TREE
#define QT_SCIENCE_TREE

#include <qwidget.h>
#include <qobject.h>
#include <qframe.h>
#include <exception>
#include <map>
#include <vector>

#include "ScienceNode.h"
#include "ListDetailsViewWidget.h"
#include "ui_ScienceTreeWidget.h"
#include "softProj\clientServer\structs.h"

/** Options for showing tokens and points in nodes */
enum EShowingOptions 
{
	/** Show in every node */
	ALL,
	
	/** Show in leaf nodes */
	LEAF, 
	
	/** Show in inner nodes */
	INNER, 
	
	/** Show nowhere */
	SHOW_NONE
};

class Ui_treeWidget; 

/** Logical representation of science tree */
class ScienceTree : public QObject
{
	Q_OBJECT

public:
	/** Constructor
	* @param treeWidget Generated tree widget from QT Designer
	* @param depth Max depth of the tree
	*/
	ScienceTree(Ui_treeWidget * treeWidget, int depth);

	/* Destructor */
	~ScienceTree();

	/** Gets free unassigned tokens
	* @return Free unassigned tokens 
	*/
	int getFreeTokens() const;
	 
	/** Sets root of the tree 
	* @param label Label for graphical representation of the root
	* @param root Graphical widget representation of the root
	* @param nodeName Name of the node for logical purposes
	*/
	void setRoot(const std::string & nodeName, QLabel * label, NodeWidget * root);

	/** Creates and appends inner node as a child of node with given name
	* @param label Label for graphical representation of the node
	* @param nodeWidget Graphical widget representation of the node
	* @param parentName Logical name of the parent of appended node
	* @param nodeName Logical name of appended node
	*/
	void appendChild(const std::string & parentName, const std::string & nodeName, QLabel * label, NodeWidget * nodeWidget);

	/** Creates and appends leaf node as a child of node with given name
	* @param label Label for graphical representation of the node
	* @param nodeWidget Graphical widget representation of the node
	* @param parentName Logical name of the parent of appended node
	* @param nodeName Logical name of appended node 
	*/
	void appendLeaf(const std::string & parentName, const std::string & nodeName, QLabel * label, NodeWidget * nodeWidget);

	/** Creates and appends composite item as a child of the leaf node given by index
	* @param leafIndex Index of leaf that will own created item
	* @param graphicalName Graphical name of composite item
	* @param parentName Logical name of the parent of appended node
	* @param nodeName Logical name of appended node 
	*/
	void appendComposite(const std::string & parentName, const std::string & nodeName, QString graphicalName);	

	/** Add tokens to the target node and propagates points
	* @param targetNode Node where to add new tokens
	* @param value Amount of tokens to add
	* @return True if operation was succesful			   
	*/
	bool addTokens(ScienceNode * targetNode, int value);

	/** Sets token multiplicators for all levels
	* @param values List of multiplicators for all levels
	* @param count Size of list with multiplicators
	*/
	void setTokenMultiplicators(double * values, int count);

	/** Hide params widget and all of its components */
	void hideParamsWidget();

	/** Shows params widget and all of its components */
	void showParamsWidget();

	/** Sets showing option of tokens in nodes
	* @param option Showing option of tokens in nodes
	*/
	void setShowTokens(EShowingOptions option);

	/** Sets showing option of points in nodes
	* @param option Showing option of points in nodes
	*/
	void setShowPoints(EShowingOptions option);

	/** Gets number of tokens assigned to node with given name
	* @param name Name of node whose number of tokens we want to get
	* @return Number of tokens assigned to the node
	*/
	unsigned long getNodeTokens(const std::string & name);

	/** Sets number of tokens assigned to node with given name
	* @param name Name of node whose number of tokens we want to set
	* @param value Number of tokens assigned to the node
	*/
	void setNodeTokens(const std::string & name, unsigned long value);

	/** Sets number of special points assigned to parameter with given name
	* @param name Name of parameter whose number of special points we want to set
	* @param value Number of special points assigned to the parameter
	*/
	void setSciencePoints(const std::string & name, unsigned long value);

	/** Gets number of special points assigned to parameter with given name
	* @param name Name of parameter whose number of special points we want to get
	* @param value Number of special points assigned to the parameter
	*/
	unsigned long getSciencePoints(const std::string & name);

	/** Sets number of real scientific points assigned to parameter with given name
	* @param name Name of parameter whose number of real scientific points we want to set
	* @param value Number of real scientific points assigned to the node
	*/
	void setRealScientificPoints(const std::string & name, unsigned long value);

	/** Clears complete state of the tree, that means all assigned tokens, percents and created scientific points.
	* It preservers structure of the tree, so only values are erased
	*/
	void clearState();

	/** Sets maximum assigned tokens to any node 
	* @param value Maximum assigned tokens to any node
	*/
	void setMaximumTokens(unsigned long value);
public slots:
	/** Slot for pressing mouse over graphical representation of some node
	* @param pressedNodeWidget Graphical widget, that was mouse pressed
	*/
	void scienceNodeMousePressed(NodeWidget * pressedNodeWidget);

	/** Slot for changing free percents in current node */
	void freePercentsChanged();

	/** Slot for changing tokens in current node 
	* @param value New amount of tokens in current node
	*/
	void tokensCountChanged(int value);

	/** Sets state of the tree, that means maximum tokens, current tokens, science points and real points
	* @param data State of the tree to set
	*/
	void setState(ScienceTreeRawUpdateData & data);

	/** Gets state of the tree, that means maximum tokens, current tokens, science points and real points
	* @return State of the tree
	*/
	sciencetree_raw_data getState();
signals:
	/** Signal for changing points in current node 
	* @param value New amount of points in current node
	*/
	void assignedPointsChanged(int value);

	/** Signal for changing free percents in current node 
	* @param value New amount of free percents in current node
	*/
	void freePercentsChangedSignal(int value);
private:
	int freeTokens_;
	ListDetailsViewWidget * itemsWidget_;
	std::vector<ScienceNode *>::size_type currentIndex_;	
	ScienceNode * selectedNode_;
	std::vector<ScienceNode *> leafsList_;

	typedef std::map<std::string, CompositeItem *>::const_iterator ParamsIterator;
	std::map<std::string, CompositeItem *> paramsList_;

	typedef std::map<std::string, ScienceNode *>::const_iterator NodesIterator;
	std::map<std::string, ScienceNode *> nodesList_;

	double * tokensMultiplicators_;
	int depth_;
	bool isNodeChangesEnabled_;
	Ui_treeWidget * treeWidget_;

	void setupNodeWidget(ScienceNode * selectedNode);
	void appendChild(const std::string & parentName, const std::string & nodeName, QLabel * label, NodeWidget * nodeWidget, bool isInner);
	void propagateMultiplicators();
	void enableNodeChanges();
	void disableNodeChanges();
	void setupParamsWidget();
	void setupBackParamsWidget();

	ScienceNode * findNode(const std::string & name);
	CompositeItem * findParameter(const std::string & name);
};

#endif