
#include <math.h>

#include "Common/World/Point.h"
#include "Player/Formation.h"

const float FIELD_LENGTH = 105.0f;
const float FIELD_WIDTH = 68.0f;
const float DEFENCE_AREA = -30.0f;
const float ATTACK_AREA = 30.0f;

const float MID_DEF_X_DIST = 15.0f;
const float MID_OFF_X_DIST = -20.0f;
const float MID_MAX_X_DIST = 25.0f;
const float DEF_MAX_X_DIST = 60.0f;
const float DEF_MIN_X_DIST = 30.0f;

const float FOR_MAX_X_DIST_OUR = 30.0f;
const float FOR_MAX_X_DIST_THEIR = 24.0f;
const float FOR_MIN_X_DIST_OUR = 0.0f;
const float FOR_MIN_X_DIST_THEIR = 8.0f;

const float FOR_MAX_DEFENCE_X_POS = -4.0f;

const float HALF_FIELD_X_POS = 0.0f;
const float MIN_BORDER_X_POS = 10.0f;

Formation::Formation()
{
	for( int i = 0; i < UNITS_COUNT; ++i ) {
		for( int j = 0; j < UNIT_MAX_PLAYERS; ++j ) {
			m_cUnits[i].m_cRelPos[j] = Point( UNDEF_POS, UNDEF_POS );
		}
	}

	m_cUnits[UNIT_2_L].m_nPlayerCount = 2;
	m_cUnits[UNIT_2_L].m_cRelPos[0] =  Point(  0.0f, -16.0f );
	m_cUnits[UNIT_2_L].m_cRelPos[1] =  Point(  0.0f,  16.0f );

	m_cUnits[UNIT_3_L].m_nPlayerCount = 3;
	m_cUnits[UNIT_3_L].m_cRelPos[0] =  Point(  0.0f, -21.0f );
	m_cUnits[UNIT_3_L].m_cRelPos[1] =  Point(  0.0f,   0.0f );
	m_cUnits[UNIT_3_L].m_cRelPos[2] =  Point(  0.0f,  21.0f );

	m_cUnits[UNIT_3_V].m_nPlayerCount = 3;
	m_cUnits[UNIT_3_V].m_cRelPos[0] =  Point( -0.5f, -21.0f );
	m_cUnits[UNIT_3_V].m_cRelPos[1] =  Point(  0.5f,   0.0f );
	m_cUnits[UNIT_3_V].m_cRelPos[2] =  Point( -0.5f,  21.0f );

	m_cUnits[UNIT_3_OV].m_nPlayerCount = 3;
	m_cUnits[UNIT_3_OV].m_cRelPos[0] = Point(  0.5f, -21.0f );
	m_cUnits[UNIT_3_OV].m_cRelPos[1] = Point( -0.5f,   0.0f );
	m_cUnits[UNIT_3_OV].m_cRelPos[2] = Point(  0.5f,  21.0f );

	m_cUnits[UNIT_4_L].m_nPlayerCount = 4;
	m_cUnits[UNIT_4_L].m_cRelPos[0] =  Point(  0.0f, -18.0f );
	m_cUnits[UNIT_4_L].m_cRelPos[1] =  Point(  0.0f,  -8.0f );
	m_cUnits[UNIT_4_L].m_cRelPos[2] =  Point(  0.0f,   8.0f );
	m_cUnits[UNIT_4_L].m_cRelPos[3] =  Point(  0.0f,  18.0f );

	m_cUnits[UNIT_4_V].m_nPlayerCount = 4;
	m_cUnits[UNIT_4_V].m_cRelPos[0] =  Point( -0.5f, -24.0f );
	m_cUnits[UNIT_4_V].m_cRelPos[1] =  Point(  0.5f,  -8.0f );
	m_cUnits[UNIT_4_V].m_cRelPos[2] =  Point(  0.5f,   8.0f );
	m_cUnits[UNIT_4_V].m_cRelPos[3] =  Point( -0.5f,  24.0f );

	m_cUnits[UNIT_4_OV].m_nPlayerCount = 4;
	m_cUnits[UNIT_4_OV].m_cRelPos[0] = Point(  0.5f, -24.0f );
	m_cUnits[UNIT_4_OV].m_cRelPos[1] = Point( -0.5f,  -8.0f );
	m_cUnits[UNIT_4_OV].m_cRelPos[2] = Point( -0.5f,   8.0f );
	m_cUnits[UNIT_4_OV].m_cRelPos[3] = Point(  0.5f,  24.0f );

	m_cUnits[UNIT_4_S].m_nPlayerCount = 4;
	m_cUnits[UNIT_4_S].m_cRelPos[0] =  Point(  0.0f, -24.0f );
	m_cUnits[UNIT_4_S].m_cRelPos[1] =  Point( -0.5f,  -8.0f );
	m_cUnits[UNIT_4_S].m_cRelPos[2] =  Point(  0.5f,   8.0f );
	m_cUnits[UNIT_4_S].m_cRelPos[3] =  Point(  0.0f,  24.0f );

	m_cUnits[UNIT_5_L].m_nPlayerCount = 5;
	m_cUnits[UNIT_5_L].m_cRelPos[0] =  Point(  0.0f, -25.6f );
	m_cUnits[UNIT_5_L].m_cRelPos[1] =  Point(  0.0f, -20.8f );
	m_cUnits[UNIT_5_L].m_cRelPos[2] =  Point(  0.0f,   0.0f );
	m_cUnits[UNIT_5_L].m_cRelPos[3] =  Point(  0.0f,  20.8f );
	m_cUnits[UNIT_5_L].m_cRelPos[4] =  Point(  0.0f,  25.6f );

	m_cUnits[UNIT_5_23].m_nPlayerCount = 5;
	m_cUnits[UNIT_5_23].m_cRelPos[0] = Point(  0.5f, -16.0f );
	m_cUnits[UNIT_5_23].m_cRelPos[1] = Point(  0.5f,  16.0f );
	m_cUnits[UNIT_5_23].m_cRelPos[2] = Point( -0.5f, -21.0f );
	m_cUnits[UNIT_5_23].m_cRelPos[3] = Point( -0.5f,   0.0f );
	m_cUnits[UNIT_5_23].m_cRelPos[4] = Point( -0.5f,  21.0f );

	m_cUnits[UNIT_5_32].m_nPlayerCount = 5;
	m_cUnits[UNIT_5_32].m_cRelPos[0] = Point(  0.5f, -21.0f );
	m_cUnits[UNIT_5_32].m_cRelPos[1] = Point(  0.5f,   0.0f );
	m_cUnits[UNIT_5_32].m_cRelPos[2] = Point(  0.5f,  21.0f );
	m_cUnits[UNIT_5_32].m_cRelPos[3] = Point( -0.5f, -16.0f );
	m_cUnits[UNIT_5_32].m_cRelPos[4] = Point( -0.5f,  16.0f );

	m_cUnits[UNIT_5_V].m_nPlayerCount = 5;
	m_cUnits[UNIT_5_V].m_cRelPos[0] =  Point( -0.5f, -25.6f );
	m_cUnits[UNIT_5_V].m_cRelPos[1] =  Point(  0.5f, -12.8f );
	m_cUnits[UNIT_5_V].m_cRelPos[2] =  Point(  0.0f,   0.0f );
	m_cUnits[UNIT_5_V].m_cRelPos[3] =  Point(  0.5f,  12.8f );
	m_cUnits[UNIT_5_V].m_cRelPos[4] =  Point( -0.5f,  25.6f );

	m_cUnits[UNIT_5_OV].m_nPlayerCount = 5;
	m_cUnits[UNIT_5_OV].m_cRelPos[0] = Point(  0.5f, -25.6f );
	m_cUnits[UNIT_5_OV].m_cRelPos[1] = Point( -0.5f, -12.8f );
	m_cUnits[UNIT_5_OV].m_cRelPos[2] = Point(  0.0f,   0.0f );
	m_cUnits[UNIT_5_OV].m_cRelPos[3] = Point( -0.5f,  12.8f );
	m_cUnits[UNIT_5_OV].m_cRelPos[4] = Point(  0.5f,  25.6f );

	m_cUnits[UNIT_6_2L].m_nPlayerCount = 6;
	m_cUnits[UNIT_6_2L].m_cRelPos[0] = Point( -0.5f, -25.0f );
	m_cUnits[UNIT_6_2L].m_cRelPos[1] = Point( -0.5f,  -5.0f );
	m_cUnits[UNIT_6_2L].m_cRelPos[2] = Point( -0.5f,  15.0f );
	m_cUnits[UNIT_6_2L].m_cRelPos[3] = Point(  0.5f, -15.0f );
	m_cUnits[UNIT_6_2L].m_cRelPos[4] = Point(  0.5f,   5.0f );
	m_cUnits[UNIT_6_2L].m_cRelPos[5] = Point(  0.5f,  25.0f );

	m_cUnits[UNIT_6_V].m_nPlayerCount = 6;
	m_cUnits[UNIT_6_V].m_cRelPos[0] =  Point( -0.5f, -26.3f );
	m_cUnits[UNIT_6_V].m_cRelPos[1] =  Point(  0.5f, -16.3f );
	m_cUnits[UNIT_6_V].m_cRelPos[2] =  Point(  0.0f,  -5.3f );
	m_cUnits[UNIT_6_V].m_cRelPos[3] =  Point(  0.0f,   5.3f );
	m_cUnits[UNIT_6_V].m_cRelPos[4] =  Point(  0.5f,  16.0f );
	m_cUnits[UNIT_6_V].m_cRelPos[5] =  Point( -0.5f,  26.3f );

	m_cUnits[UNIT_6_OV].m_nPlayerCount = 6;
	m_cUnits[UNIT_6_OV].m_cRelPos[0] = Point(  0.5f, -26.3f );
	m_cUnits[UNIT_6_OV].m_cRelPos[1] = Point( -0.5f, -16.3f );
	m_cUnits[UNIT_6_OV].m_cRelPos[2] = Point(  0.0f,  -5.3f );
	m_cUnits[UNIT_6_OV].m_cRelPos[3] = Point(  0.0f,   5.3f );
	m_cUnits[UNIT_6_OV].m_cRelPos[4] = Point( -0.5f,  16.3f );
	m_cUnits[UNIT_6_OV].m_cRelPos[5] = Point(  0.5f,  26.3f );

	// inicializacia timu
	m_nFormationId = FORMATION_622;
	m_nTeamSide = SIDE_NONE;

	m_nUnitDef = UNIT_6_2L;
	m_nUnitMid = UNIT_2_L;
	m_nUnitFor = UNIT_2_L;
	m_dDefBallDist = 1.0f;
	m_dMidBallDist = 1.0f;
	m_dForBallDist = 1.0f;

	// FORMATION_622
	m_eRole[0][0] = PR_GoalKeeper;
	m_eRole[0][1] = m_eRole[0][2] = m_eRole[0][3] = PR_Defensman;
	m_eRole[0][4] = m_eRole[0][5] = m_eRole[0][6] = PR_Defensman;
	m_eRole[0][7] = m_eRole[0][8] = PR_Midfielder;
	m_eRole[0][9] = m_eRole[0][10] = PR_Forward;

	// FORMATION_532
	m_eRole[1][0] = PR_GoalKeeper;
	m_eRole[1][1] = m_eRole[1][2] = m_eRole[1][3] = PR_Defensman;
	m_eRole[1][4] = m_eRole[1][5] = PR_Defensman;
	m_eRole[1][6] = m_eRole[1][7] = m_eRole[1][8] = PR_Midfielder;
	m_eRole[1][9] = m_eRole[1][10] = PR_Forward;

	// FORMATION_523
	m_eRole[2][0] = PR_GoalKeeper;
	m_eRole[2][1] = m_eRole[2][2] = m_eRole[2][3] = PR_Defensman;
	m_eRole[2][4] = m_eRole[2][5] = PR_Defensman;
	m_eRole[2][6] = m_eRole[2][7] = PR_Midfielder;
	m_eRole[2][8] = m_eRole[2][9] = m_eRole[2][10] = PR_Forward;
	
	// FORMATION_433
	m_eRole[3][0] = PR_GoalKeeper;
	m_eRole[3][1] = m_eRole[3][2] = m_eRole[3][3] = PR_Defensman;
	m_eRole[3][4] = PR_Defensman;
	m_eRole[3][5] = m_eRole[3][6] = m_eRole[3][7] = PR_Midfielder;
	m_eRole[3][8] = m_eRole[3][9] = m_eRole[3][10] = PR_Forward;

	
	// FORMATION_343
	m_eRole[4][0] = PR_GoalKeeper;
	m_eRole[4][1] = m_eRole[4][2] = m_eRole[4][3] = PR_Defensman;
	m_eRole[4][4] = m_eRole[4][5] = m_eRole[4][6] = PR_Midfielder;
	m_eRole[4][7] = PR_Midfielder;
	m_eRole[4][8] = m_eRole[4][9] = m_eRole[4][10] = PR_Forward;

	
	// FORMATION_334
	m_eRole[5][0] = PR_GoalKeeper;
	m_eRole[5][1] = m_eRole[5][2] = m_eRole[5][3] = PR_Defensman;
	m_eRole[5][4] = m_eRole[5][5] = m_eRole[5][6] = PR_Midfielder;
	m_eRole[5][7] = m_eRole[5][8] = m_eRole[5][9] = PR_Forward;
	m_eRole[5][10] = PR_Forward;
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetUnitFromRawUnit( int nPlayersCount, int nRawUnit )
// ---------------------------------------------------------------------------
// Description:
//		vrati index kontretnej jednotky pre dany pocet hracov v nej na zaklade 
//		vseobecneho rozlozenia - nRawUnit
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nPlayersCount
//		int nRawUnit
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetUnitFromRawUnit( int nPlayersCount, int nRawUnit )
{
	switch( nPlayersCount )
	{
		case 2 :
			// pre dvoch hracov ine rozostavenie nemame
			return UNIT_2_L;

		case 3 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_3_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_3_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_3_OV;
				}
			}
			break;

		case 4 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_4_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
						return UNIT_4_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_4_OV;

					case UNIT_STRONG_CENTER:
						return UNIT_4_S;
				}
			}
			break;

		case 5 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
						return UNIT_5_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_5_V;

					case UNIT_CENTER_DEFENCE:
						return UNIT_5_OV;

					case UNIT_TWO_LINES:
					case UNIT_2LINES_DEFENCE:
						return UNIT_5_23;

					case UNIT_2LINES_ATTACK:
						return UNIT_5_32;
				}
			}
			break;

		case 6 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_6_2L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_6_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_6_OV;
				}
			}
			break;
	}

	// chyba 
	return UNIT_6_2L;
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetPlayersRoleCount( int nFormationId, FormationRole eRole )
// ---------------------------------------------------------------------------
// Description:
//		vrati pocet hracov, ktori vo formacii nFormationId maju rolu eRole
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormationId
//		FormationRole eRole
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetPlayersRoleCount( int nFormationId, FormationRole eRole )
{
	int ret_val = 0;

	for( int i = 0; i < 11; ++i ) {
		if ( m_eRole[nFormationId][i] == eRole ) {
			++ret_val;
		}
	}

	return ret_val;
}

void Formation::Init( int nTeamSide, int nFormationId, int nDefUnit, int nMidUnit, int nForUnit )
{
	m_nTeamSide = nTeamSide;
	m_nFormationId = nFormationId;
	m_nUnitDef = nDefUnit;
	m_nUnitMid = nMidUnit;
	m_nUnitFor = nForUnit;
}

void Formation::InitRawUnits( int nTeamSide, int nFormationId, int nDefUnit, int nMidUnit, int nForUnit )
{
	m_nTeamSide = nTeamSide;
	m_nFormationId = nFormationId;

	m_nUnitDef = nDefUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Defensman ), nDefUnit );
	m_nUnitMid = nMidUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Midfielder ), nMidUnit );
	m_nUnitFor = nForUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Forward ), nForUnit );;
}

FormationRole Formation::GetPlayerRole( int nTeamSide, int nPlayerId )
{
	return m_eRole[m_nFormationId][nPlayerId];
}

int Formation::GetUnitIndex( int nTeamSide, int nPlayerId )
{
	FormationRole eRole = GetPlayerRole( nTeamSide, nPlayerId );

	int nDefCnt, nMidCnt;

	nDefCnt = 0;
	nMidCnt = 0;
	int nFormationId = m_nFormationId;
	
	for( int index = 0; index < PLAYER_COUNT; ++index ) {
		if ( m_eRole[nFormationId][index] == PR_Defensman ) {
			++nDefCnt;
		}

		if ( m_eRole[nFormationId][index] == PR_Midfielder ) {
			++nMidCnt;
		}
	}

	switch( eRole ) {
		case PR_GoalKeeper :
			return -1;

		case PR_Defensman :
			return int(nPlayerId - 1 );

		case PR_Midfielder :
			return int(nPlayerId - 1 - nDefCnt );

		case PR_Forward :
			return int(nPlayerId - 1 - nDefCnt - nMidCnt );
	}

	return -1;
}

int Formation::GetUnitId( int nTeamSide, FormationRole eRole )
{
	switch( eRole ) {
		case PR_GoalKeeper :
			return -1;

		case PR_Defensman :
			return m_nUnitDef;

		case PR_Midfielder :
			return m_nUnitMid;

		case PR_Forward :
			return m_nUnitFor;
	}

	return -1;
}

Point Formation::GetPlayerPosition( int nTeamSide, int nPlayerId )
{
	FormationRole eRole = GetPlayerRole( nTeamSide, nPlayerId );

	if ( eRole == PR_GoalKeeper ) {
		return GOALIE_POS;
	}

	Point cOriginPos = GetUnitPosition( nTeamSide, nPlayerId );

	switch( eRole ) {
		case PR_Defensman :            
			cOriginPos = Point(cOriginPos.GetX() + (DEF_ORIGIN_DIST * m_dDefBallDist), cOriginPos.GetY());
			break;

		case PR_Midfielder :
            cOriginPos = Point(cOriginPos.GetX() + (MID_ORIGIN_DIST * m_dMidBallDist), cOriginPos.GetY());			
			break;

		case PR_Forward :
            cOriginPos = Point(cOriginPos.GetX() + (FOR_ORIGIN_DIST * m_dForBallDist), cOriginPos.GetY());						
			break;
	}

	return cOriginPos;
}

Point Formation::GetUnitPosition( int nTeamSide, int nPlayerId )
{	
	FormationRole eRole = GetPlayerRole( nTeamSide, nPlayerId );
	
	if ( eRole == PR_GoalKeeper ) {
		return GOALIE_POS;
	}

	float width = UNIT_WIDTH;
	float scale = 1.0f;
	switch( eRole ) {
		case PR_Defensman :
//			width = PlayerConfig.UnitXSizeDef();
//			scale = PlayerConfig.ScaleYPosDef();
            // GP
            width = 15.0f;
            scale = 1.0f;
			break;

		case PR_Midfielder :
//			width = PlayerConfig.UnitXSizeMid();
//			scale = PlayerConfig.ScaleYPosMid();
            // GP
            width = 15.0f;
            scale = 1.0f;
			break;

		case PR_Forward :
//			width = PlayerConfig.UnitXSizeFor();
//			scale = PlayerConfig.ScaleYPosFor();
            // GP
            width = 15.0f;
            scale = 1.0f;
			break;
	}
	
	int nUnitIndex = GetUnitIndex( nTeamSide, nPlayerId );
	int nUnitId = GetUnitId( nTeamSide, eRole );
	
	//ASSERT( nUnitIndex >= 0 && nUnitIndex <= UNIT_MAX_PLAYERS );
	Point ret_val = m_cUnits[nUnitId].m_cRelPos[nUnitIndex];
	
	// uprav x-ovu suradnicu podla sirky jednotky
	ret_val.SetX(ret_val.GetX() * width); 
	ret_val.SetY(ret_val.GetY() * scale);

	return ret_val;
}

Point Formation::GetPlayerPosition( int nPlayerId, const Point& cBallPos )
{
	return GetPlayerPosition( m_nTeamSide, nPlayerId - 1, cBallPos, true, true );
}

Point Formation::GetPlayerPosition( int nTeamSide, int nPlayerId, const Point& cBallPos, bool followx, bool followy )
{
	//Point cOriginPos = m_cRelPos[nPlayerId];
	Point cOriginPos = GetPlayerPosition( 0, nPlayerId );
	//cOriginPos.GetX() *= m_nTeamSide;
	Point cBall = cBallPos;
	cBall.SetX( cBall.GetX() * m_nTeamSide);


	if ( followx ) {
		cOriginPos = AdjustXPosition( nTeamSide, nPlayerId, cOriginPos, cBall );
		// uprav x-ovu suradnicu o posunutie v ramci jednotky
		Point originPos = GetUnitPosition( nTeamSide, nPlayerId );
		cOriginPos.SetX(originPos.GetX() + cOriginPos.GetX());

		// posun pozicie od krajov ihriska, v zmysle x-ovej osi
		if ( cOriginPos.GetX() > ( FIELD_LENGTH / 2.0f - MIN_BORDER_X_POS ) ) {
			cOriginPos.SetX( FIELD_LENGTH / 2.0f - MIN_BORDER_X_POS );
		}
		else {
			if ( cOriginPos.GetX() < ( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS ) ) {
				cOriginPos.SetX( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS );
			}
		}
	}

	if( followy ) {
		cOriginPos = AdjustYPosition( nTeamSide, nPlayerId, cOriginPos, cBall );
	}

	cOriginPos.SetX(nTeamSide * cOriginPos.GetX());

	return cOriginPos;
}

Point Formation::AdjustXPosition( int nTeamSide, int nPlayerId, const Point& cOriginPos, const Point& cBallPos )
{
	Point ret_val;
	FormationRole player_role = GetPlayerRole( nTeamSide, nPlayerId );

	switch( player_role ) {
		case PR_GoalKeeper:
			ret_val = cOriginPos;
			break;

		case PR_Defensman:
			ret_val = AdjustDefPositionX( cOriginPos, cBallPos );
			break;
			
		case PR_Midfielder:
			ret_val = AdjustMidPositionX( cOriginPos, cBallPos );
			break;
			
		case PR_Forward:
			ret_val = AdjustForPositionX( cOriginPos, cBallPos );
			break;
	}

	return ret_val; 
}

Point Formation::AdjustYPosition( int nTeamSide, int nPlayerId, const Point& cOriginPos, const Point& cBallPos )
{
	Point cRetVal = cOriginPos;
	float fLow = 0.1f;
	float fHi = 0.5f;

	if ( nTeamSide < 0 ) {
		nTeamSide = 0;
	}

	FormationRole eRole = GetPlayerRole( nTeamSide, nPlayerId );
	int nUnitId = GetUnitId( nTeamSide, eRole );
	int nMyIndex = GetUnitIndex( nTeamSide, nPlayerId );
	int p_cnt = m_cUnits[nUnitId].m_nPlayerCount;

	float scale = 1.0f;
	float power = 1.0f;
	switch( eRole ) {
		case PR_Defensman :
//			scale = PlayerConfig.ScaleYPosDef();
//			power = PlayerConfig.FollowYPowerDef();
            // GP
            scale = 1.0f;
            power = 1.25f;
			break;

		case PR_Midfielder :
//			scale = PlayerConfig.ScaleYPosMid();
//			power = PlayerConfig.FollowYPowerMid();
            // GP
            scale = 1.0f;
            power = 1.25f;
			break;

		case PR_Forward :
//			scale = PlayerConfig.ScaleYPosFor();
//			power = PlayerConfig.FollowYPowerFor();
            // GP
            scale = 1.0f;
            power = 1.25f;
			break;
	}

	float fMaxDiff = fabsf( cBallPos.GetY() - ( m_cUnits[nUnitId].m_cRelPos[nMyIndex].GetY() * scale ) );
	int nFarThenMe = 0;

	if ( p_cnt > 3 ) {
		// ak su v jednotke viac ako traja hraci, najdalej stoji hrac sa nepriblizuje k k lopte v zmysle y-ovej suradnice
		float fYDiff;

		for( int i = 0; i < p_cnt; ++i ) {
			fYDiff = fabsf( cBallPos.GetY() - ( m_cUnits[nUnitId].m_cRelPos[i].GetY() * scale ) );

			if ( fYDiff > fMaxDiff ) {
				nFarThenMe++;
			}
		}

		if ( p_cnt < 6 ) {
			if ( nFarThenMe == 0 ) {
				return cRetVal;
			}
		}
		else {
			if ( nFarThenMe <= 1 ) {
				return cRetVal;
			}
		}
	}
	
	//float diff = cBallPos.GetY() - cOriginPos.GetY();
	float diff = cBallPos.GetY() - ( m_cUnits[nUnitId].m_cRelPos[nMyIndex].GetY() * scale );
	float x_mem = ( ( FIELD_WIDTH - fabsf( diff ) ) / FIELD_WIDTH );
	
	if ( x_mem > FIELD_WIDTH / 2 ) {
		x_mem *= x_mem;
	}
	
	float r =  x_mem * ( fHi - fLow ) + fLow; 
	cRetVal.SetY( (diff * r * power ) + cRetVal.GetY());

	return cRetVal;
}

Point Formation::AdjustDefPositionX( const Point& player_pos, const Point& ball_pos )
{
	Point ret_val;
	ret_val = player_pos;

	if ( ball_pos.GetX() < DEFENCE_AREA ) {
		ret_val.SetX(ball_pos.GetX());

		if ( ret_val.GetX() < ( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS ) ) {
			ret_val.SetX( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS );
		}		
		
		return ret_val;
	}
	
	if ( ball_pos.GetX() > ATTACK_AREA ) {
		ret_val.SetX( HALF_FIELD_X_POS - 4.0f );
		return ret_val;
	}

	// lopta na nasej polovici
	if ( ball_pos.GetX() < HALF_FIELD_X_POS ) {
		ret_val.SetX( ball_pos.GetX() - DEF_MIN_X_DIST);

		if ( ret_val.GetX() < DEFENCE_AREA ) {
			ret_val.SetX(DEFENCE_AREA);
		}

		return ret_val;
	}

	// lopta na superovej polovici, ale nie v utocnej oblasti
	ret_val.SetX(ball_pos.GetX() - DEF_MIN_X_DIST);

	if ( ret_val.GetX() > ( ( FIELD_LENGTH / 2.0f ) - 4.0f ) ) {
		ret_val.SetX( ( FIELD_LENGTH / 2.0f ) - 4.0f);
	}

	return ret_val;
}

Point Formation::AdjustMidPositionX( const Point& player_pos, const Point& ball_pos )
{
	Point ret_val;
	ret_val = player_pos;

	if ( ball_pos.GetX() < DEFENCE_AREA ) {
		ret_val.SetX( ball_pos.GetX() + MID_DEF_X_DIST );

		if ( ret_val.GetX() < DEFENCE_AREA ) {
			ret_val.SetX( DEFENCE_AREA);
		}

		return ret_val;
	}

	if ( ball_pos.GetX() > ATTACK_AREA ) {
		ret_val.SetX( ball_pos.GetX() + MID_OFF_X_DIST);

		if ( ret_val.GetX() > ATTACK_AREA ) {
			ret_val.SetX( ATTACK_AREA );
		}

		return ret_val;
	}

// TODO
// GP OffenseMidfielders - bool -  agresivni strednopoliari 
/*
	if ( PlayerConfig.OffenseMidfielders() ) {
		float k = ( -MID_MAX_X_DIST - MID_MAX_X_DIST ) / ( ATTACK_AREA - DEFENCE_AREA );
		ret_val.GetX() = ball_pos.GetX() + MID_MAX_X_DIST + k * ( ball_pos.GetX() - DEFENCE_AREA );
	}
	else {
*/
		const float k = ( MID_OFF_X_DIST - MID_DEF_X_DIST ) / ( ATTACK_AREA - DEFENCE_AREA );
		ret_val.SetX( ball_pos.GetX() + k * ( ball_pos.GetX() - DEFENCE_AREA ) + MID_DEF_X_DIST);
//	}

	return ret_val;
}

Point Formation::AdjustForPositionX( const Point& player_pos, const Point& ball_pos )
{
	float min_dst;
	float max_dst;

	// super ma loptu, tvarme sa ze super ma loptu
	min_dst = FOR_MIN_X_DIST_THEIR;
	max_dst = FOR_MAX_X_DIST_THEIR;

	Point ret_val;
	ret_val = player_pos;

	float k = ( min_dst - max_dst  ) / ( ATTACK_AREA - ( FIELD_LENGTH / 2.0f ) );
	ret_val.SetX( ball_pos.GetX() + k * ( ball_pos.GetX() )  + max_dst);

	if ( fabsf( ret_val.GetX() - ball_pos.GetX() ) > max_dst ) {
		ret_val.SetX(ball_pos.GetX() + max_dst);
	}

	// stred ihriska nech utocnici neprekracuju 
	if ( ret_val.GetX() < FOR_MAX_DEFENCE_X_POS ) {
		ret_val.SetX(HALF_FIELD_X_POS);
		return ret_val;
	}
	
	if ( fabsf( ret_val.GetX() - ball_pos.GetX() ) < min_dst ) {
		ret_val.SetX( ball_pos.GetX() + min_dst);
	}

	if ( ret_val.GetX() > ( FIELD_LENGTH / 2.0f - 10.0f ) ) {
		ret_val.SetX(( FIELD_LENGTH / 2.0f - 10.0f ));
	}

	return ret_val;
}
