#include "stdafx.h"
#include "MobileMicrobe.h"

#include "CellWarsGameManager.h"
#include "Infrastructure\Camera.h"
#include "Cell.h"
#include "Macrophage.h"
#include "Util\MathUtil.h"

#include <math.h>

//#include <stdio.h>

const float MobileMicrobe::LINEAR_VELOCITY_DAMPING_FACTOR = 1;//50.0f;
const float MobileMicrobe::EXPONENTIAL_VELOCITY_DAMPING_FACTOR = 3.0f;
const float MobileMicrobe::OWN_MOVEMENT_THRESHOLD_VELOCITY = 3.0f;

MobileMicrobe::MobileMicrobe() : currentVelocity(), lastPosition(), ignoreDampingAndInertia(false)
{
}

MobileMicrobe::~MobileMicrobe()
{
}

void MobileMicrobe::ReceiveMessage(Message *m)
{
	Actor::ReceiveMessage(m);
}

void MobileMicrobe::Render()
{
	Actor::Render();
}

void MobileMicrobe::Update(float dt)
{
	Actor::Update(dt);

	respectTheLimits();
	if (!ignoreDampingAndInertia && currentVelocity.Length() > 0)
	{
		applyDamping(dt);
		applyInertia(dt);
	}
	turnToVelocityVector(dt);

	lastPosition = this->GetPosition();
}

void MobileMicrobe::respectTheLimits()
{
	if (GetPosition().X < theCamera.GetWorldMinVertex().X)
	{
		if (currentVelocity.X < -OWN_MOVEMENT_THRESHOLD_VELOCITY)
			currentVelocity.X = -currentVelocity.X;
		else
			currentVelocity.X = OWN_MOVEMENT_THRESHOLD_VELOCITY;
	}
	if (GetPosition().X > theCamera.GetWorldMaxVertex().X)
	{
		if (currentVelocity.X > OWN_MOVEMENT_THRESHOLD_VELOCITY)
			currentVelocity.X = -currentVelocity.X;
		else
			currentVelocity.X = -OWN_MOVEMENT_THRESHOLD_VELOCITY;
	}
	if (GetPosition().Y < theCamera.GetWorldMinVertex().Y)
	{
		if (currentVelocity.Y < -OWN_MOVEMENT_THRESHOLD_VELOCITY)
			currentVelocity.Y = -currentVelocity.Y;
		else
			currentVelocity.Y = OWN_MOVEMENT_THRESHOLD_VELOCITY;
	}
	if (GetPosition().Y > theCamera.GetWorldMaxVertex().Y)
	{
		if (currentVelocity.Y > OWN_MOVEMENT_THRESHOLD_VELOCITY)
			currentVelocity.Y = -currentVelocity.Y;
		else
			currentVelocity.Y = -OWN_MOVEMENT_THRESHOLD_VELOCITY;
	}
}

void MobileMicrobe::applyDamping(float dt)
{
	//LINEAR DAMPING
	if (currentVelocity.Length() <= LINEAR_VELOCITY_DAMPING_FACTOR * dt)
		currentVelocity *= 0;
	else
	{
		Vector2 friction(currentVelocity);
		friction.Normalize();
		friction *= LINEAR_VELOCITY_DAMPING_FACTOR * dt;
		currentVelocity -= friction;
	}

	//EXPONENTIAL DAMPING
	currentVelocity *= exp(EXPONENTIAL_VELOCITY_DAMPING_FACTOR * -dt);
}

void MobileMicrobe::applyInertia(float dt)
{
	this->SetPosition(this->GetPosition() + currentVelocity * dt);
}

void MobileMicrobe::turnToVelocityVector(float dt)
{
	static const float MIN_VELOCITY_TO_TURN = 2.0f;
	Vector2 lastFrameVelocity((GetPosition() - lastPosition) / dt);
	if (lastFrameVelocity.Length() > MIN_VELOCITY_TO_TURN)
	{
		float nominalTurnAngle = MathUtil::ToDegrees(MathUtil::AngleFromVector(lastFrameVelocity));
		float deltaTurnAngle = GetRotation() - nominalTurnAngle;
		float finalTurnAngle = GetRotation() - 0.5f * deltaTurnAngle;
		this->SetRotation(finalTurnAngle);
		//std::cout << "turn finalTurnAngle = " << finalTurnAngle << ", speed = (" << 
		//	lastFrameMovement.X << ", " << lastFrameMovement.Y << ")" << std::endl;
	}
}