#include "stdafx.h"
#include "Model.h"

/**
 Constructor for the CurrentYearGrowth class. Initializes
 all vectors and diameter to zero values.
*/
MhsModel::CurrentYearGrowth::CurrentYearGrowth(void)
{
	name = S"cyg";

	tip3dPoint.X=0.0;
	tip3dPoint.Y=0.0;
	tip3dPoint.Z=0.0;

	base3dPoint.X=0.0;
	base3dPoint.Y=0.0;
	base3dPoint.Z=0.0;

	ref3dPoint.X=0.0;
	ref3dPoint.Y=0.0;
	ref3dPoint.Z=0.0;

	baseDiameter = 0;
}

/**
	Desctructor stub.
*/
MhsModel::CurrentYearGrowth::~CurrentYearGrowth(void)
{
}

/**
	Sets the 3 dimensional coordinate's of the CYG's tip. Deep copy.
	@param v a __gc pointer to a vector containing the values to assign.
*/
void MhsModel::CurrentYearGrowth::setTip(Vector3 __gc* v)
{
	tip3dPoint.X=v->X;
	tip3dPoint.Y=v->Y;
	tip3dPoint.Z=v->Z;
}

/**
	Sets the 3 dimensional coordinate's of the CYG's base. Deep copy.
	@param v a __gc pointer to a vector containing the values to assign.
*/
void MhsModel::CurrentYearGrowth::setBase(Vector3 __gc* v)
{
	base3dPoint.X=v->X;
	base3dPoint.Y=v->Y;
	base3dPoint.Z=v->Z;
}

/**
	Sets the 3 dimensional coordinate's of the CYG's random reference point. Deep copy.
	@param v a __gc pointer to a vector containing the values to assign.
*/
void MhsModel::CurrentYearGrowth::setRef(Vector3 __gc* v)
{
	ref3dPoint.X=v->X;
	ref3dPoint.Y=v->Y;
	ref3dPoint.Z=v->Z;
}

/**
	Returns a string representation of the CYG. Mostly for debugging.
	@return a __gc pointer to a string
*/
String __gc* MhsModel::CurrentYearGrowth::toString()
{
	StringBuilder __gc* sb = new StringBuilder;

	sb->Append("\t\t[");
	sb->Append(name);
	sb->Append(",b(");
	sb->Append(base3dPoint.X);
	sb->Append(",");
	sb->Append(base3dPoint.Y);
	sb->Append(",");
	sb->Append(base3dPoint.Z);
	sb->Append("),");

	sb->Append("t(");
	sb->Append(tip3dPoint.X);
	sb->Append(",");
	sb->Append(tip3dPoint.Y);
	sb->Append(",");
	sb->Append(tip3dPoint.Z);
	sb->Append("),");

	sb->Append("r(");
	sb->Append(ref3dPoint.X);
	sb->Append(",");
	sb->Append(ref3dPoint.Y);
	sb->Append(",");
	sb->Append(ref3dPoint.Z);
	sb->Append("),");

	sb->Append("d=");
	sb->Append(baseDiameter);
	sb->Append("]");



	return sb->ToString();
}

/**
	Converts this CYG to a comma separated list of export values as defined in the design document.
	@return a string representing a CYG's part of a CSV export line
*/
String __gc* MhsModel::CurrentYearGrowth::toExport()
{
	System::Text::StringBuilder __gc* sb = new System::Text::StringBuilder;

	sb->Append(distanceFrom3dRefPoint());
	sb->Append(",");
	sb->Append(length());
	sb->Append(",");
	sb->Append(baseDiameter);
	sb->Append(",");
	sb->Append(calcDepthLevel());

	return sb->ToString();
}

/**
	Uses the 3 dimensional distance formula to calculate the distance from the
	CYG's base point and the CYG's reference point.
	@return a float that is the linear distance between the points
*/
float MhsModel::CurrentYearGrowth::distanceFrom3dRefPoint()
{
	return abs(sqrt(	pow(ref3dPoint.X - base3dPoint.X, 2) + 
						pow(ref3dPoint.Y - base3dPoint.Y, 2) + 
						pow(ref3dPoint.Z - base3dPoint.Z, 2) ));
}

/**
	Uses the 3 dimensional distance formula to calculate the distance from the
	CYG's base point and the CYG's tip point.
	@return a float that is the linear distance between the points
*/
float MhsModel::CurrentYearGrowth::length()
{
	return abs(sqrt(	pow(tip3dPoint.X - base3dPoint.X, 2) + 
						pow(tip3dPoint.Y - base3dPoint.Y, 2) + 
						pow(tip3dPoint.Z - base3dPoint.Z, 2) ));
}

/**
	Uses the CYG's z-axis to determine what depth level the CYG is at.
	The radio pen is 1.5 meters off the ground. So values between < -500
	are in the 1 meter level, between -500 and 500 are the 2 meter level and above
	500 are the 3 meter level.
	@return a float that is the linear distance between the points
*/
int MhsModel::CurrentYearGrowth::calcDepthLevel()
{
	int depthLevel;
	if( abs(base3dPoint.Z) <= 500 ){
		depthLevel = 2;
	} else if( base3dPoint.Z < -500 ){
		depthLevel = 1;
	} else if( base3dPoint.Z > 500 ){
		depthLevel = 3;
	}
	return depthLevel;
}


/**
	Exercises an instance of CYG to verify component. Internal work product.
*/
String __gc* MhsModel::CurrentYearGrowth::unitTest()
{

	StringBuilder __gc* sb = new StringBuilder();
	CurrentYearGrowth __gc* cyg = new CurrentYearGrowth();
	Vector3 *origin = __nogc new Vector3(0.0f,0.0f,0.0f);
	Vector3 *xaxis = __nogc new Vector3(1.0f,0.0f,0.0f);
	Vector3 *yaxis = __nogc new Vector3(0.0f,1.0f,0.0f);
	Vector3 *zaxis = __nogc new Vector3(0.0f,0.0f,1.0f);
	Vector3 *OneOneOne = __nogc new Vector3(1.0f,1.0f,1.0f);

	// test: length
	cyg->setBase(origin);
	cyg->setTip(xaxis);
	cyg->baseDiameter=1;
	sb->Append("Length ");
	sb->Append(cyg->toString());
	sb->Append(" == 1? ");
	sb->Append(cyg->length());
	sb->Append("\n");

	cyg->setBase(origin);
	cyg->setTip(OneOneOne);
	sb->Append("Length ");
	sb->Append(cyg->toString());
	sb->Append(" == sqrt(3) =~ 1.7320508? ");
	sb->Append(cyg->length());
	sb->Append("\n");

	// test: distance
	cyg->setBase(xaxis);
	cyg->setTip(OneOneOne);
	cyg->setRef(origin);
	sb->Append("Distance ");
	sb->Append(cyg->toString());
	sb->Append(" == 1? ");
	sb->Append(cyg->distanceFrom3dRefPoint());
	sb->Append("\n");

	cyg->setBase(OneOneOne);
	cyg->setTip(yaxis);
	cyg->setRef(xaxis);
	sb->Append("Distance ");
	sb->Append(cyg->toString());
	sb->Append(" == sqrt(2) =~ 1.4142135? ");
	sb->Append(cyg->distanceFrom3dRefPoint());
	sb->Append("\n");


	// test: depth levels
	cyg->base3dPoint.Z=0;
	sb->Append("Depth ");
	sb->Append(cyg->toString());
	sb->Append(" == 2? ");
	sb->Append(cyg->calcDepthLevel());
	sb->Append("\n");

	cyg->base3dPoint.Z=500;
	sb->Append("Depth ");
	sb->Append(cyg->toString());
	sb->Append(" == 2? ");
	sb->Append(cyg->calcDepthLevel());
	sb->Append("\n");

	cyg->base3dPoint.Z=501;
	sb->Append("Depth ");
	sb->Append(cyg->toString());
	sb->Append(" == 3? ");
	sb->Append(cyg->calcDepthLevel());
	sb->Append("\n");

	cyg->base3dPoint.Z=-600;
	sb->Append("Depth ");
	sb->Append(cyg->toString());
	sb->Append(" == 1? ");
	sb->Append(cyg->calcDepthLevel());
	sb->Append("\n");

	// test: export
	cyg->setBase(xaxis);
	cyg->setTip(OneOneOne);
	cyg->setRef(origin);
	sb->Append("Export ");
	sb->Append(cyg->toString());
	sb->Append(" == ");
	sb->Append(" ,1,1.414214,1,2 ? ");
	sb->Append(cyg->toExport());
	sb->Append("\n");

	return sb->ToString();
}
