#include "Player/PlayerSkills.h"
#include "Player/PlayerTactics.h"
#include "Common/Main.h"
#include "Common/Tasks.h"
#include "Common/Support/Debug.h"
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <limits.h>




void PlayerSkills::DecodeEnemyLang(const char* msg)
{
	if(langEnemyFarmari) langEnemyFarmari = CanBeFarmari(msg);
	TXTN("CanBeFarmari %d", langEnemyFarmari);

	if(world->state->GetSimTime() > 500)
	{
		if(langEnemyFarmari) langEnemyFarmari = UpdateWorldFarmari(msg);
	}
	else
	{
		if(langEnemyFarmari) langEnemyFarmari = DecodeAndValidate(msg);

	}
}


bool PlayerSkills::CanBeFarmari(const char* msg)
{
	if(strlen(msg) != 10) return false;

	for(int i = 0; i < 10; i++)
	{
		// Convert to <0, 71>
		unsigned char num;
		if((msg[i] >= 'a') && (msg[i] <= 'z')) num = ((char) msg[i]) - 'a';
		else if((msg[i] >= 'A') && (msg[i] <= 'Z')) num = ((char) msg[i]) - 'A' + 26;
		else if((msg[i] >= '0') && (msg[i] <= '9')) num = ((char) msg[i]) - '0' + 52;
		else if(msg[i] == '+') num = 62; else if(msg[i] == '-') num = 63;
		else if(msg[i] == '*') num = 64; else if(msg[i] == '/') num = 65;
		else if(msg[i] == '(') num = 66; else if(msg[i] == ')') num = 67;
		else if(msg[i] == '.') num = 68; else if(msg[i] == '?') num = 69;
		else if(msg[i] == '<') num = 70; else if(msg[i] == '>') num = 71;
		else { return false; }
	}

	return true;
}

bool PlayerSkills::DecodeAndValidate(const char* msg)
{
	// Ignore too short messages
	if(strlen(msg) != 10) return false;

	// Find out information about sender
	Player player(world);
	player.SetUniform(0);

	// Parse his message
	// Each character is converted to number from <0, 71> (we ignore '_' and ' ')
	// The number is the split to five parts: two 3-state and three 2-state (3*3*2*2*2=72)
	// We use the three parts and the <0, 71> numbers to store data in an effective way
	// See also PlayerSkills::SendInfo()
	unsigned char parts[10][6];

	for(int i = 0; i < 10; i++)
	{
		// Convert to <0, 71>
		unsigned char num;
		if((msg[i] >= 'a') && (msg[i] <= 'z')) num = ((char) msg[i]) - 'a';
		else if((msg[i] >= 'A') && (msg[i] <= 'Z')) num = ((char) msg[i]) - 'A' + 26;
		else if((msg[i] >= '0') && (msg[i] <= '9')) num = ((char) msg[i]) - '0' + 52;
		else if(msg[i] == '+') num = 62; else if(msg[i] == '-') num = 63;
		else if(msg[i] == '*') num = 64; else if(msg[i] == '/') num = 65;
		else if(msg[i] == '(') num = 66; else if(msg[i] == ')') num = 67;
		else if(msg[i] == '.') num = 68; else if(msg[i] == '?') num = 69;
		else if(msg[i] == '<') num = 70; else if(msg[i] == '>') num = 71;
		else { WARNN("failed decoding for hear (%i->%c)", i, msg[i]); return false; }

		// Split to parts
		parts[i][0] = num;
		parts[i][1] = num % 3; num /= 3;
		parts[i][2] = num % 3; num /= 3;
		parts[i][3] = num % 2; num /= 2;
		parts[i][4] = num % 2; num /= 2;
		parts[i][5] = num % 2; num /= 2;
	}

	Point* flags = world->params->flags;

/*	DBGN("---");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][0]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][1]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][2]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][3]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][4]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][5]); DBGN("");
*/

	// Parts allocation:
	// - = free, X = player x coord, Y = player y coord
	// D = player direction, S = player speed
	// 1(3) XYDS----YY
	// 2(3) XYDS----DX
	// 3(2) XYDS----DX
	// 4(2) XYDS----SX
	// 5(2) XYDS----YX
	// This has to be the same as in SendInfo().

	// X coordinate of player (uses 72,3,2,2,2 see above)
	int tmp = (((parts[0][0] * 3 + parts[9][2]) * 2 + parts[9][3]) * 2 + parts[9][4]) * 2 + parts[9][5];
//	DBGN("tmp_x %i", tmp);
	
	player.pos.SetX(-(
		float(tmp) * (flags[R0].GetX() - flags[L0].GetX()) / 
		float(72 * 3 * 2 * 2 * 2) + flags[L0].GetX()));

	// Y coordinate of player (uses 72,3,3,2 see above)
	tmp = ((parts[1][0] * 3 + parts[9][1]) * 3 + parts[8][1]) * 2 + parts[8][5];
//	DBGN("tmp_y %i", tmp);
	
	player.pos.SetY(-( 
		float(tmp) * (flags[B0].GetY() - flags[T0].GetY()) / 
		float(72 * 3 * 3 * 2) + flags[T0].GetY()));

	// Direction of player (uses 72,3,2 see above)
//	tmp = (parts[2][0] * 3 + parts[8][2]) * 2 + parts[8][3];
//	float dir = float(tmp) * 2.0f * M_PI / float(72 * 3 * 2);
//	DBGN("tmp_dir %i ang %0.3f", tmp, dir);

	// Speed of player (uses 72,2 see above)
//	tmp = parts[3][0] * 2 + parts[8][4];
//	DBGN("tmp_spd %i", tmp);
//	float spd = 
//		float(tmp) * (world->params->server->player_speed_max + world->params->player->player_speed_max_delta_max) / 
//		float(72 * 2);

	player.vel.SetX(0);
	player.vel.SetY(0);
	player.SetAge(MAX_PLAYER_AGE - 10);

	
	return true;

}



bool PlayerSkills::UpdateWorldFarmari(const char* msg)
{
	if(strlen(msg) != 10) return false;

	// Find out information about sender
	Player player(world);
	player.SetUniform(0);

	unsigned char parts[10][6];

	for(int i = 0; i < 10; i++)
	{
		// Convert to <0, 71>
		unsigned char num;
		if((msg[i] >= 'a') && (msg[i] <= 'z')) num = ((char) msg[i]) - 'a';
		else if((msg[i] >= 'A') && (msg[i] <= 'Z')) num = ((char) msg[i]) - 'A' + 26;
		else if((msg[i] >= '0') && (msg[i] <= '9')) num = ((char) msg[i]) - '0' + 52;
		else if(msg[i] == '+') num = 62; else if(msg[i] == '-') num = 63;
		else if(msg[i] == '*') num = 64; else if(msg[i] == '/') num = 65;
		else if(msg[i] == '(') num = 66; else if(msg[i] == ')') num = 67;
		else if(msg[i] == '.') num = 68; else if(msg[i] == '?') num = 69;
		else if(msg[i] == '<') num = 70; else if(msg[i] == '>') num = 71;
		else { WARNN("failed decoding for hear (%i->%c)", i, msg[i]); return false; }

		// Split to parts
		parts[i][0] = num;
		parts[i][1] = num % 3; num /= 3;
		parts[i][2] = num % 3; num /= 3;
		parts[i][3] = num % 2; num /= 2;
		parts[i][4] = num % 2; num /= 2;
		parts[i][5] = num % 2; num /= 2;
	}

	Point* flags = world->params->flags;

	int tmp = (((parts[0][0] * 3 + parts[9][2]) * 2 + parts[9][3]) * 2 + parts[9][4]) * 2 + parts[9][5];

	
	player.pos.SetX(-(
		float(tmp) * (flags[R0].GetX() - flags[L0].GetX()) / 
		float(72 * 3 * 2 * 2 * 2) + flags[L0].GetX()));

	tmp = ((parts[1][0] * 3 + parts[9][1]) * 3 + parts[8][1]) * 2 + parts[8][5];

	
	player.pos.SetY(-( 
		float(tmp) * (flags[B0].GetY() - flags[T0].GetY()) / 
		float(72 * 3 * 3 * 2) + flags[T0].GetY()));


	player.vel.SetX(0);
	player.vel.SetY(0);
	player.SetAge(MAX_PLAYER_AGE - 10);
	player.SetSide(THEIR);

	if(!IsThereEnemy(player.pos))
	{
		TXTN("Pridavam nepriatela na zaklade zvukovej informacie od protihracov");
		world->AddEnemyPlayer(player);
		//world->enemies.Add(player);
	}

	return true;
}


bool PlayerSkills::IsThereEnemy(Point &pos)
{
	int s = world->enemies.GetSize();

	if(s > 0)
	{
		int idx = -1;
		float dist=1000000.f;
		
		for(int i=0; i<s; i++)
		{
			float d = (world->enemies[i].pos - pos).GetLength();
          
			if(d < dist)
			{
				idx = i;
				dist = d;
			}
        }

        if(idx >= 0)
        {
			float me_dist = (world->enemies[idx].pos - world->me->pos).GetLength();
			float rad = me_dist * .05f;
          
			if( dist <= rad )
			{
				TXTN("Na pozicii %f, %f sa uz nachadza nejaky protihrac", pos.GetX(), pos.GetY());
				return true;
			}
        }
    }

	TXTN("Na pozicii %f, %f sa nenachadza protihrac", pos.GetX(), pos.GetY());
	return false; 
}



/*
float PlayerSkills::GetRunProb(Point from, Point to, float distance, int time)
{
	float realDist = (from - to).GetLength();
	float maxDist = time * world->params->server->player_speed_max;
	float prob;

	if(realDist > maxDist) 
		prob = 0.f;
	else
		prob = realDist/maxDist;

	TXTN("Je %f pravdepodobnost ze protihrac s pozicie %f, %f je teraz na pozicii %f, %f cyklov na presun %d realDist %f maxDist %f distance %f", 
		from.GetX(), prob, from.GetY(), to.GetX(), to.GetY(), time, realDist, maxDist, distance);

	return prob;
}



void PlayerSkills::AddEnemyPlayer(Player player)
{
	int maxindex = -1;
	float maxprob = 0.0f, prob;

	if(player.GetUniform() == 0)
	{
		TXTN("1. Registrujem hraca neviem jeho cislo snazim sa zistit ci to nie je niekto koho som videl");

		for(int i=0; i<world->enemies.GetSize(); i++)
		{
			float len = (world->me->pos - world->enemies[i].pos).GetLength();
			int age = world->enemies[i].GetAge();

			if(world->enemies[i].GetUniform() != 0)
			{
				TXTN("Pravdepodobnost pre hraca s cislom %d", world->enemies[i].GetUniform());
				prob = GetRunProb(world->enemies[i].pos, player.pos, len, age);
			}
			else
			{
				if(age >= ((MAX_PLAYER_AGE - 10))
				{
					// hrac pridany pomocou zvukovej informacie ktoru nam sam poslal
					if(player.GetAge() >= ((MAX_PLAYER_AGE - 10))
					{
						TXTN("Pravdepodobnost pre hraca ktory sa pridal zvukom a znova ho mozno pocujem");
						prob = GetRunProb(world->enemies[i].pos, player.pos, len, age - player.GetAge());

					}
					else
					{
						TXTN("Pravdepodobnost pre hraca ktory sa pridal zvukom a mozno ho vidime za chrbtom");
						prob = GetRunProb(world->enemies[i].pos, player.pos, len, player.GetAge() - MAX_PLAYER_AGE + 10 + age);
					}
				}
				else
				{
					// hraca som videl vo svojej blizkosti
					if(player.GetAge() >= ((MAX_PLAYER_AGE - 10))
					{
						TXTN("Pravdepodobnost pre hraca ktoreho som videl za chrbtom a mozno ho pocujem");
						prob = GetRunProb(world->enemies[i].pos, player.pos, len, player.GetAge() - MAX_PLAYER_AGE + 10 + age);

					}
					else
					{
						TXTN("Pravdepodobnost pre hraca ktoreho som videl za chrbtom a znova ho mozno vidim");
						prob = GetRunProb(world->enemies[i].pos, player.pos, len, age - player.GetAge());
					}

				}


			}

			if(prob > maxprob)
			{
				maxprob = prob;
				maxindex = i;
			}
		}

		if(maxindex != -1)
		{
			TXTN("Protihraca na pozicii %f, %f treba odstranit s pravdepodobnostou %f", world->enemies[maxindex].pos.GetX(), 
				world->enemies[maxindex].pos.GetY(), maxprob);

		}
	}
	else
	{
		TXTN("2. Vidim protihraca s cislom %d zistujeme ci to bol niekto koho sme uz videli", player.GetUniform());
		int index = world->FindEnemyIndex(player.GetUniform());

		if(index == -1)
		{
			for(int i=0; i<world->enemies.GetSize(); i++)
			{
				if(world->enemies[i].GetAge() < (MAX_PLAYER_AGE - 10)) continue;
				if(world->enemies[i].GetUniform() == 0)
				{
					float len = (world->me->pos - world->enemies[i].pos).GetLength();
					prob = GetRunProb(world->enemies[i].pos, player.pos, len, world->enemies[i].GetAge() - MAX_PLAYER_AGE + 10);

					if(prob > maxprob)
					{
						maxprob = prob;
						maxindex = i;
					}

				}
			}

			if(maxindex != -1)
			{
				TXTN("Protihraca na pozicii %f, %f treba odstranit s pravdepodobnostou %f", world->enemies[maxindex].pos.GetX(), 
				world->enemies[maxindex].pos.GetY(), maxprob);
			}

		}
	}

}


*/
