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

#include "Player/World/Myself.h"
#include "Common/Support/Debug.h"
#include <limits.h>

Myself::Myself(World* w) : SimPlayer(w)
{
	effort = 0;
	stamina = 0;
	vwidth = NORMAL_VIEW;

	dirValid = true;

	lastSeenTime = -2;
	seeCount = 0;
	SetSide(OUR);
}

Myself::Myself(const Myself& player) : SimPlayer(player)
{
	effort = player.effort;
	stamina = player.stamina;
	vwidth = player.vwidth;

	lastSeenPos = player.lastSeenPos;
	lastSeenTime = player.lastSeenTime;
}

Myself& Myself::operator=(const Myself& player)
{
	if(&player == this) return *this;

	Player::operator=(player);

	effort = player.effort;
	stamina = player.stamina;
	vwidth = player.vwidth;

	lastSeenPos = player.lastSeenPos;
	lastSeenTime = player.lastSeenTime;

	return *this;
}

bool Myself::IsLookingAt(Point point) const
{
	Angle minAng = DegAngle(0);
	Angle maxAng = DegAngle(0);
	
	switch(vwidth)
	{
	case NARROW_VIEW:
		minAng = DegAngle(-world->params->server->visible_angle / 4);
		maxAng = DegAngle(world->params->server->visible_angle / 4);
		break;
	case NORMAL_VIEW:
		minAng = DegAngle(-world->params->server->visible_angle / 2);
		maxAng = DegAngle(world->params->server->visible_angle / 2);
		break;
	case WIDE_VIEW:
		minAng = DegAngle(-world->params->server->visible_angle);
		maxAng = DegAngle(world->params->server->visible_angle);
		break;
	}
	
	Vector diff = point - pos;
	Angle angle = diff.GetAngle() - absDir - neckDir;

	if(minAng <= angle && angle <= maxAng) return true;
	else return false;
}

bool Myself::Recalculate(const SENSE_BODY* sb, const VISUAL_INFO* vi)
{
	int i;
	Angle viewDir;

	// Do we have at least some information?
	if(vi->landmarkCnt == 0 && vi->lineCnt == 0) return false;

	// Compute view direction using lines
	if(vi->lineCnt == 0)
	{
		// I do not see any lines
		viewDir = absDir + neckDir;
	}
	else
	{
		float maxDist = 0;

		// I see some lines, iterate through them
		for(i = 0; i < vi->lineCnt; i++)
		{
			if(maxDist <= vi->lines[i].dist)
			{
				maxDist = vi->lines[i].dist;
				Angle hlpDir = DegAngle(vi->lines[i].dir);

				switch(vi->lines[i].type)
				{
				case Top:
					if(hlpDir >= DegAngle(0)) viewDir = -hlpDir;
					else viewDir = DegAngle(-180) - hlpDir;
					break;
				case Bottom:
					if(hlpDir >= DegAngle(0)) viewDir = DegAngle(180) - hlpDir;
					else viewDir = -hlpDir;
					break;
				case Left:
					if(hlpDir >= DegAngle(0)) viewDir = DegAngle(-90) - hlpDir;
					else viewDir = DegAngle(90) - hlpDir;
					break;
				case Right:
					if(hlpDir >= DegAngle(0)) viewDir = DegAngle(90) - hlpDir;
					else viewDir = DegAngle(-90) - hlpDir;
					break;
				default:
					// This should not happen...
					break;
				}
			}
		}
	}

	// We already know view direction (viewDir). What is the nearest flag?
	int nearestFlag = -1;
	float nearestDist = 0;
	for(i = 1; i < vi->landmarkCnt; i++)
	{
		if(vi->landmarks[i].distValid && (vi->landmarks[i].dist < nearestDist || nearestFlag == -1))
		{
			nearestFlag = i;
			nearestDist = vi->landmarks[i].dist;
		}
	}

	// Were any suitable flags found?
	if(vi->landmarkCnt == 0 || nearestFlag == -1) return true;

	// Find out where is the flag and what is our current vector to it.
	Point flagPos = world->params->flags[vi->landmarks[nearestFlag].type];
	Vector flagVec = PolarVector(
		vi->landmarks[nearestFlag].dist, viewDir + DegAngle(vi->landmarks[nearestFlag].dir));
	
	
	// Set my position from the flag position and vector
	pos = flagPos - flagVec;
	
	// Set my absolute direction by subtracting my head direction
	absDir = viewDir - neckDir;
	
	// Set my speed
	vel = PolarVector(sb->speedSize, viewDir + DegAngle(sb->speedDirection));

	// Other stuff
	dirValid = true;
	
	return true;
}

void Myself::Step()
{
	pos = pos + vel;
	vel *= type->player_decay;
}

Myself::~Myself()
{
}
