#include <QtGui>
#include <math.h>

#include "ScienceNode.h"
#include "ScienceTree.h"
#include "NodeWidget.h"


void ScienceInnerNode::bubblePoints(int beforePoints, int value, double bubbledMultiplier)
{
	for (NodesIterator it = children_.begin(); it != children_.end(); ++it)
	{
		(*it)->addPoints(beforePoints, value, bubbledMultiplier);
	}
}

void ScienceLeafNode::bubblePoints(int, int, double)
{
	// Nedělej nic
}

void ScienceNode::addTokens(int value)
{
	// Za každý přidaný token se také přidá jeden bod. Zde pozor, nejde udělat
	// jenom například setPoints(assignedTokens_), protože počet tokenů a bodů
	// nemusí být pokaždé stejný
	addPoints(0, value, 0);

	// Po přidání tokenů se samozřejmě zvedne počet tokenů
	assignedTokens_ += value;

	nodeWidget_->setupTokensSize();
	nodeWidget_->setupPointsSize();

	refreshWidget();
}

void ScienceNode::setTokensMultiplicator(double value)
{
	pointsMultiplier_ = value;
}

void ScienceNode::refreshWidget()
{
	QString text;

	if (showTokens_ && showPoints_)
	{
		text = name_ + " (" + QString::number(assignedTokens_) + "|" + QString::number(assignedPoints_) + ")";
	}
	else if (showTokens_)
	{
		text = name_ + " (" + QString::number(assignedTokens_) + ")";
	}
	else if (showPoints_)
	{
		text = name_ + " (" + QString::number(assignedPoints_) + ")";
	}
	else
	{
		text = name_;
	}

	label_->setText(text);
	nodeWidget_->update();
}

void ScienceNode::addPoints(int parentsToken, int value, double bubbledMultiplier)
{
	double totalMultiplier;

	int beforeParamValue = value;

	if (bubbledMultiplier > 0)
	{
		totalMultiplier = bubbledMultiplier * pointsMultiplier_;

		assignedPoints_ = assignedPoints_ - (int)(totalMultiplier * parentsToken);
		value = parentsToken + value;

		assignedPoints_ = assignedPoints_ + (int)(totalMultiplier * value);
	}
	else
	{
		totalMultiplier = 1;
		assignedPoints_ += value;
	}

	bubblePoints(parentsToken + assignedTokens_, beforeParamValue, totalMultiplier);
	
	refreshWidget();
	nodeWidget_->setupPointsSize();
}

int ScienceNode::getAssignedTokens() const 
{
	return assignedTokens_;
}

int ScienceNode::getAssignedPoints() const
{
	return assignedPoints_;
}

void ScienceNode::setAssignedTokens(int value)
{		 
	int addedTokens = value - assignedTokens_;

	addTokens(addedTokens);
}

QString ScienceNode::getName()
{
	return name_;
}

bool ScienceLeafNode::appendChild(ScienceNode *)
{
	throw new std::exception("ScienceLeafNode cannot have children");
}

ScienceNode::ScienceNode(const std::string & nodeName, NodeWidget * node, QLabel * label)
{
	label_ = label;
	parent_ = NULL;

	name_ = QString(label->text());
	logicalName_ = nodeName;

	assignedTokens_ = 0; 
	assignedPoints_ = 0;
	fullAssignedPoints_ = 0;

	maximumTokens_ = 0;

	nodeWidget_ = node;
	nodeWidget_->setLogicalNode(this);
	nodeWidget_->setLabel(label);

	refreshWidget();
}

NodeWidget * ScienceNode::getNodeWidget()
{
	return nodeWidget_;
}

void ScienceNode::setParent(ScienceNode * parent)
{
	parent_ = parent;
}

ScienceNode * ScienceNode::getParent()
{
	return parent_;
}

int ScienceNode::getDepth()
{
	return depth_;
}

void ScienceNode::setDepth(int value)
{
	depth_ = value;
}

std::vector<CompositeItem *> & ScienceInnerNode::getCompositeItems()
{
	throw new std::exception("Inner node cannot have composite items");
}

int ScienceInnerNode::getCompositeCountAct() 
{
	throw new std::exception("Inner node cannot have composite items");
}

void ScienceInnerNode::appendComposite(CompositeItem *)
{
	throw new std::exception("Inner mode cannot have composite child");
}

bool ScienceInnerNode::appendChild(ScienceNode * child)
{
	children_.push_back(child);

	child->setParent(this);
	child->setDepth(depth_ + 1);
	return true;
}

bool ScienceInnerNode::isInner()
{
	return true;
}

int ScienceInnerNode::getFreePercents()
{
	throw new std::exception("Inner node cannot have percents");
}

ScienceInnerNode::ScienceInnerNode(const std::string & nodeName, NodeWidget * node, QLabel * label) 
	: ScienceNode(nodeName, node, label)
{	
}

std::vector<CompositeItem *> & ScienceLeafNode::getCompositeItems()
{
	return compositeItems_;
}

int ScienceLeafNode::getCompositeCountAct() 
{
	return compositeItems_.size();
}

int ScienceLeafNode::getFreePercents()
{
	return freePercents_;
}

ScienceLeafNode::ScienceLeafNode(const std::string & nodeName, NodeWidget * node, QLabel * label) : ScienceNode(nodeName, node, label)
{	
	freePercents_ = 0;
}

bool ScienceLeafNode::assignedPercentsChanged(CompositeItem * item, int value)
{
	int addedPercents = value - item->getAssignedPercents();

	if (freePercents_ >= addedPercents)
	{
		freePercents_ -= addedPercents;
		item->setAssignedPercents(value);
		return true;
	}

	return false;
}

void ScienceLeafNode::appendComposite(CompositeItem * composite)
{
	compositeItems_.push_back(composite);
	composite->setParentLeaf(this);
	composite->setAssignedPercents(100);
}

bool ScienceLeafNode::isInner()
{
	return false;
}

ScienceLeafNode::~ScienceLeafNode()
{
	for (ParamsIterator it = compositeItems_.begin(); it != compositeItems_.end(); ++it) 
	{
		delete (*it);
	}
}

void ScienceNode::setShowPoints(bool value)
{
	showPoints_ = value;
	refreshWidget();
}

void ScienceNode::setShowTokens(bool value)
{
	showTokens_ = value;
	refreshWidget();
}

bool ScienceNode::isLeaf()
{
	return !isInner();
}

void ScienceInnerNode::clearState() {
	assignedPoints_ = 0;
	assignedTokens_ = 0;
}

void ScienceLeafNode::clearState() {
	assignedPoints_ = 0;
	assignedTokens_ = 0;
	freePercents_ = 100;

	for (ParamsIterator it = compositeItems_.begin(); it != compositeItems_.end(); ++it) {
		(*it)->clearState();
	}
}

void ScienceNode::setMaximumTokens(unsigned long value) {
	maximumTokens_ = value;
}

unsigned long ScienceNode::getMaximumTokens() {
	return maximumTokens_;
}