#include "Coach/CoachKernel.h"
#include "Common/Tasks.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <limits.h>

/**
 * Collect information of behaviour of opponent players to determine their heterotype
 *
 * \returns false -> not recognized, != 0 -> oppenent heterotype recognized
 * \author Eugen Krizo
 */
bool
CoachKernel::SpyOthers( const COACH_VISUAL_INFO* vi )
{
	Vector speed;
	DegAngle rotation;
	float speedXRotation;
	bool drop = false;		///< invalidate relative values
	bool recognized = false; ///< was recognized

#ifndef TURBO_COACH_FFO
//	if ( visualDumpFile )
//		fwrite( vi, sizeof( COACH_VISUAL_INFO ), 1, visualDumpFile );
#endif	// TURBO_COACH
	log->printf( "eZo09: time:%d, playMode:%d\n", vi->time, GetPlayMode() );

	/// providing at the momment the play mode was changed to 'play on' wait one step
	/// to obtain relative values
	if ( GetPlayMode() != PM_PlayOn )
		return false;
	else if ( delaySpy ) {
		delaySpy = false;
		DBGN( "eZo05: SpyOthers - skipping time: %d", vi->time );
		drop = true;
	}

	if ( !drop ) {
		Vector speedDelta;

		speedDelta = vi->ball.speed - spyBall.lastVelocity.val * serverParams->ball_decay;

		spyBall.lastPosition.val = vi->ball.pos;
		spyBall.lastPosition.time = vi->time;
		spyBall.lastVelocity.val = vi->ball.speed;
		spyBall.lastVelocity.time = vi->time;

		DBGN("eZo11: ball speedDelta: %lf - %d, lastKick( %d, %d )", speedDelta.GetLength(), vi->time, lastKick.who, lastKick.when );
	}

	for( int i = 0; i < vi->theirCount; i++ ) 
	{
		/* acceleration */
		if ( spyTheirPlayer[i].acceleration.val < vi->their[i].speed.GetLength() )
		{
			spyTheirPlayer[i].acceleration.val = vi->their[i].speed.GetLength();
			spyTheirPlayer[i].acceleration.time = vi->time;
		}

		/* speed */
		speed = vi->their[i].pos - spyTheirPlayer[i].lastPosition.val;
		if ( !drop && spyTheirPlayer[i].speed.val < speed.GetLength() &&\
				spyTheirPlayer[i].lastPosition.time + 1 == vi->time )
		{
			spyTheirPlayer[i].speed.val = speed.GetLength();
			spyTheirPlayer[i].speed.time = vi->time;
/////////////////////////////////////////////////////////////////////
			if 	( spyTheirPlayer[i].speed.val > 1.16 && spyTheirPlayer[i].heteroType <= 0 )
			{
				int id=-1;
				{
					int idMiddle=-1;
					float dash_p_r=-1.0;
					float stamina_inc_max=-1.0;
					float realSpeed = -1.0;
					for (int i=0; i<playerParams->player_types; i++){
						float curRealSpeedMax = CalcRealSpeedMax(i) ;
						if (realSpeed<curRealSpeedMax){
							realSpeed = curRealSpeedMax;
							stamina_inc_max = playerTypes[i].stamina_inc_max;
							idMiddle = id;
							id=i;
						}
						else if (realSpeed==curRealSpeedMax && stamina_inc_max<playerTypes[i].stamina_inc_max)
						{
							realSpeed = curRealSpeedMax;
							stamina_inc_max = playerTypes[i].stamina_inc_max;
							idMiddle = id;
							id=i;
						}
					}
				}
				spyTheirPlayer[i].heteroType = id;
				recognized = true;
				DBGN("eZo10: recognized: (%d, %d), type: %d, speed: %f", i, vi->time, id, spyTheirPlayer[i].speed.val);
			}
/////////////////////////////////////////////////////////////////////
		}
		spyTheirPlayer[i].lastPosition.val = vi->their[i].pos;
		spyTheirPlayer[i].lastPosition.time = vi->time;

		/* rotation */
		rotation = vi->their[i].bodyFacingDir;
		rotation -= spyTheirPlayer[i].lastAngle.val;
		if ( !drop && spyTheirPlayer[i].lastAngle.time > 0 && \
			spyTheirPlayer[i].rotation.val <  rotation.GetAbsDeg() )
		{	
			spyTheirPlayer[i].rotation.val = rotation.GetAbsDeg();
			spyTheirPlayer[i].rotation.time = vi->time;
		}
		spyTheirPlayer[i].lastAngle.val = vi->their[i].bodyFacingDir;
		spyTheirPlayer[i].lastAngle.time = vi->time;


		/* speedXRotation */
		speedXRotation = speed.GetLength() * rotation.GetAbsRad();
		//DBGN("eZo05: speedXRotation: (%f, %d, %d)", speedXRotation, i, vi->time);
		if ( !drop && spyTheirPlayer[i].speedXRotation.val < speedXRotation )
		{
			spyTheirPlayer[i].speedXRotation.val = speedXRotation ;
			spyTheirPlayer[i].speedXRotation.time = vi->time;
		}

		/* console output */
		if ( vi->time % 10 == 0 )
			DBGN("eZo04: speed(%f, %d), position( %f, %f), acceleration(%f, %d), rotation(%f, %d), speedXrotation(%f, %d)", \
				spyTheirPlayer[i].speed.val, spyTheirPlayer[i].speed.time, \
				spyTheirPlayer[i].acceleration.val, spyTheirPlayer[i].acceleration.time,\
				spyTheirPlayer[i].rotation.val, spyTheirPlayer[i].rotation.time, \
				spyTheirPlayer[i].speedXRotation.val, spyTheirPlayer[i].speedXRotation.time);

		log->printf( "eZo04: %d, %d: position(%f,%f), angle(%f), speed(%f, %d), acceleration(%f, %d), rotation(%f, %d), speedXrotation(%f, %d)\n", \
				vi->time, i, vi->their[i].pos.GetX(), vi->their[i].pos.GetY(), vi->their[i].bodyFacingDir, \
				spyTheirPlayer[i].speed.val, spyTheirPlayer[i].speed.time, \
				spyTheirPlayer[i].acceleration.val, spyTheirPlayer[i].acceleration.time,\
				spyTheirPlayer[i].rotation.val, spyTheirPlayer[i].rotation.time, \
				spyTheirPlayer[i].speedXRotation.val, spyTheirPlayer[i].speedXRotation.time);
	}

	if ( vi->time % 10 == 0 )
		DBGN("eZo02: step %d", vi->time);

	return recognized;
}

float CoachKernel::CalcRealSpeedMax(int type)
{
	PLAYER_TYPE* player_type = &playerTypes[type];
	float max_accel = 100.0f * player_type->dash_power_rate * player_type->effort_max;
    float real_speed_max = max_accel / (1.0f - player_type->player_decay);
    if ( real_speed_max > player_type->player_speed_max )
    {
        real_speed_max = player_type->player_speed_max;
    }
	return real_speed_max;
}

