// ################################
// ##  Tridy pevnosti (ne tridy  ##
// ##  cpp, ale ve smyslu typy)  ##
// ################################

#include "fortress_classes.h"

#include <math.h>

#include "fortress_skelet.h"

#ifdef _DEBUG
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#endif

// ################################
// ################################

fortressClass * fortressClassClass::deriveNewFortress(hangarClass * hangar, unsigned long long &titaniumForConstruction, bool divineBuilding)
{
	if (!divineBuilding)
	{
		if ((        hangar) && (FT_BASE == this->getClassType()))
		{
			return 0;
		}
		if ((NULL == hangar) && (FT_SHIP == this->getClassType()))
		{
			return 0;
		}
	}
	
	itemDimensionsClass newFortressDimensions(titaniumForConstruction);
	if (hangar)
	{
		newFortressDimensions.length_ = hangar->actualLength();
		newFortressDimensions.width_  = hangar->actualWidth() ;
		newFortressDimensions.height_ = hangar->actualHeight();
		if (!fitShipIntoWeightAndHangar(&newFortressDimensions))
		{
			return 0;
		}
	}
	else
	{
		if (!getDimensionsByWeight(&newFortressDimensions))
		{
			return 0;
		}
	}

	unsigned long long fortressWeight              = newFortressDimensions.weight_;
	unsigned long long fortressStructuralIntegrity = ullNumberFromScale(this->minTotalStructuralIntegrity_, this->maxTotalStructuralIntegrity_, (double)(this->maxWeight_ - this->minWeight_), (double)(max(0, fortressWeight - this->minWeight_)));
	double             fortressLength              = newFortressDimensions.length_;
	double             fortressWidth               = newFortressDimensions.width_ ;
	double             fortressHeight              = newFortressDimensions.height_;

	fortressClass * result = NULL;
	if (FT_BASE == this->getClassType())
	{
		result = new baseClass(this->getClassName(),
			                   fortressWeight,
							   fortressStructuralIntegrity,
							   fortressLength,
							   fortressWidth,
							   fortressHeight,
							   this->getID(),
							   divineBuilding);
	}
	if (FT_SHIP == this->getClassType())
	{
		result = new shipClass(this->getClassName(),
			                   fortressWeight,
							   fortressStructuralIntegrity,
							   fortressLength,
							   fortressWidth,
							   fortressHeight,
							   this->getID());
	}
 
	return result;
};

// --------------------------------

bool fortressClassClass::fitShipIntoWeightAndHangar(itemDimensionsClass * dimensionsLimits)
{
	double requiredLength = 0;
	double requiredWidth  = 0;
	double requiredHeight = 0;

	// funkce getDimensionsByWegith rovnou upravi i buildingTitanium, ktere je predano referenci
	if (!getDimensionsByWeight(dimensionsLimits->weight_, requiredLength, requiredWidth, requiredHeight))
	{
		dimensionsLimits->weight_ = 0;
		dimensionsLimits->length_ = 0;
		dimensionsLimits->width_  = 0;
		dimensionsLimits->height_ = 0;
		return 0;
	}

	double worstLinearRatio = dimensionsLimits->ratioForSomethingToFitInHere(requiredLength, requiredWidth, requiredHeight);
	if (1 <= worstLinearRatio)
	{
		dimensionsLimits->length_ = requiredLength;
		dimensionsLimits->width_  = requiredWidth ;
		dimensionsLimits->height_ = requiredHeight;
	}
	else
	{
		dimensionsLimits->weight_ = ullRound((double)dimensionsLimits->weight_ * pow(worstLinearRatio, (double)3));
		dimensionsLimits->length_ = worstLinearRatio * requiredLength;
		dimensionsLimits->width_  = worstLinearRatio * requiredWidth ;
		dimensionsLimits->height_ = worstLinearRatio * requiredHeight;
		if ((dimensionsLimits->weight_ < this->minWeight_) || (this->maxWeight_ < dimensionsLimits->weight_))
		{
			dimensionsLimits->weight_ = 0;
			dimensionsLimits->length_ = 0;
			dimensionsLimits->width_  = 0;
			dimensionsLimits->height_ = 0;
			return 0;
		}
	}

	return 1;
};

// --------------------------------

bool fortressClassClass::getDimensionsByWeight(unsigned long long &buildingTitanium, double &length, double &width, double &height)
{
	if (buildingTitanium < this->minWeight_)
	{
		buildingTitanium = 0;
		length           = 0;
		width            = 0;
		height           = 0;
		return 0;
	}
	buildingTitanium = min(buildingTitanium, this->maxWeight_);

	double cubicRatio  = ((double)(buildingTitanium)) / ((double)(this->maxWeight_));
	double linearRatio = pow(cubicRatio, (double)1 / (double)3);

	length = linearRatio * this->maxLength_;
	width  = linearRatio * this->maxWidth_ ;
	height = linearRatio * this->maxHeight_;

	return 1;
};

// --------------------------------

bool fortressClassClass::getDimensionsByWeight(itemDimensionsClass * fortressDimensions)
{
	return this->getDimensionsByWeight(fortressDimensions->weight_, fortressDimensions->length_, fortressDimensions->width_, fortressDimensions->height_);
};

// --------------------------------

bool fortressClassClass::shipFitsIntoHangar(hangarClass * hangar, unsigned long long buildingTitanium)
{
	if (FT_SHIP != this->getClassType())
	{
		return 0;
	}

	if ((buildingTitanium < this->minWeight_) ||
		(buildingTitanium > this->maxWeight_))
	{
		return 0;
	}

	double length = 0;
	double width  = 0;
	double height = 0;

	if ((!getDimensionsByWeight(buildingTitanium, length, width, height)) ||
		(hangar->actualLength() < length                                ) ||
		(hangar->actualWidth()  < width                                 ) ||
		(hangar->actualHeight() < height                                ))
	{
		return 0;
	}
	
	return 1;
};

// ################################
// ################################