/**
 * \file Ball.cpp
 * \date 12.04.2003
 *
 * Interface for the Ball class
 */

#include "Player/World/Ball.h"
#include "Player/World/World.h"

Ball::Ball(World* w) : Movable(w)
{
	valid = false;
	lastSeenTime = -2;
}

Ball::Ball(const Ball& ball) : Movable(ball)
{
	valid = ball.valid;
	lastSeenPos = ball.lastSeenPos;
	lastSeenTime = ball.lastSeenTime;
}

Ball& Ball::operator=(const Ball& ball)
{
	if(&ball == this) return *this;
	Movable::operator=(ball);

	valid = ball.valid;
	lastSeenPos = ball.lastSeenPos;
	lastSeenTime = ball.lastSeenTime;

	return *this;
}

void Ball::Recalculate(const SENSE_BODY* sb, const VISUAL_INFO* vi)
{		
	// I am looking this way
	Angle viewDir = world->me->GetAbsDir() + world->me->GetNeckDir();

	// I see a ball and I know its distance and direction, compute its absolute position
	Angle angle = viewDir + DegAngle(vi->ball.dir);
	pos = world->me->pos + PolarVector(vi->ball.dist, angle);

	WORLD_RECALC_DBG("  ball: viewDir: %f, dir: %f", viewDir.GetDeg(), vi->ball.dir);

	// Do I see also its speed?
	if(vi->ball.changesValid)
	{
		// From TsinghuAeolus2002
		Vector rpos = PolarVector(vi->ball.dist, DegAngle(vi->ball.dir));
		rpos /= rpos.GetLength();

		Vector rvel = RectVector(
			vi->ball.distChange * rpos.GetX() - vi->ball.dirChange * M_PI / 180.f * vi->ball.dist * rpos.GetY(),
			vi->ball.distChange * rpos.GetY() + vi->ball.dirChange * M_PI / 180.f * vi->ball.dist * rpos.GetX());
			
		// Rotate rvel
		rvel += viewDir;
		vel = world->me->vel + rvel;

//		vel = world->me->vel + PolarVector(vi->ball.distChange, angle) + 
//			PolarVector(vi->ball.dist * dirCh, angle).OrthoLeft();

		WORLD_RECALC_DBG("  ball: changesValid, pos: (%f, %f), vel: (%f, %f)", pos.GetX(), pos.GetY(), vel.GetX(), vel.GetY());
	}
	else
	{
		// I do not see ball speed, use the CMU method
		if((vi->ball.dist <= world->params->server->visible_distance) &&
			(world->state->GetSimTime() == lastSeenTime + 1) &&
			(world->state->GetSimTime() == world->me->GetLastSeenTime() + 1))
		{
			Vector correction = 
				world->me->vel / world->me->type->player_decay - 
				(world->me->pos - world->me->GetLastSeenPos());
				
			vel = (pos - lastSeenPos + correction);
			vel *= world->params->server->ball_decay;
		}

		// On collision, multiply ball speed by -0.1
		bool ballCollision = false;
		TXTN("  ball : ball distance %f, mindistance %f", vi->ball.dist, world->me->type->player_size + world->params->server->ball_size + 0.05);
		if(vi->ball.dist <= world->me->type->player_size + world->params->server->ball_size + 0.05)
		{
			WORLD_RECALC_DBG("  ball : collision ball distance %f", vi->ball.dist);
			ballCollision = true;
		}

		if(ballCollision && (world->state->GetSimTime() > lastSeenTime)) vel *= -0.1f;

		WORLD_RECALC_DBG("  ball: CMU method, pos: (%f, %f), vel: (%f, %f)", pos.GetX(), pos.GetY(), vel.GetX(), vel.GetY());
	}

	// I see the ball just now
	age = 0;
	lastSeenPos = pos;
	lastSeenTime = world->state->GetSimTime();
	valid = true;
}

void Ball::Step()
{
	pos = pos + vel;
	vel *= world->params->server->ball_decay;
	age++;
}

Ball::~Ball()
{
}
