/**
 * \file PlayerSkills.h
 * \date 14.04.2002
 *
 * Interface for the PlayerSkills class
 */

#ifndef MODULES_PLAYERSKILLS_H
#define MODULES_PLAYERSKILLS_H

#include "Player/PlayerKernel.h"
#include "Common/Interfaces/Commands.h"
#include "Common/World/Point.h"
#include "Common/Main.h"
#include "Common/Support/List.h"

#define POS_TOL 1.0f

//#define CATCH_DBGN DBGN
#define CATCH_DBGN DO_NOTHING

//#define SKILLS_DBGN DBGN
#define SKILLS_DBGN DO_NOTHING

//#define SHOUT_DBGN DBGN
#define SHOUT_DBGN DO_NOTHING

//#define UBLK_DBGN DBGN
#define UBLK_DBGN DO_NOTHING


// Roztoce => USE_OLD_INTERCEPT && !USE_ALTERNATIVE_INTERCEPT
// Matus   => !USE_OLD_INTERCEPT && !USE_ALTERNATIVE_INTERCEPT
// TrePe   => !USE_OLD_INTERCEPT && USE_ALTERNATIVE_INTERCEPT
#define USE_OLD_INTERCEPT
//#define USE_ALTERNATIVE_INTERCEPT

enum PlayerRole
{
	PR_Goalie,
	PR_Player
};

/**
 * \class PlayerSkills
 * \author Daniel Novomesky
 * \author Marek Lehuta
 * \brief PlayerSkills module
 */

class PlayerSkills : public PlayerKernel
{
public:
// Construction and destruction
	PlayerSkills(
		const char* name = "PlayerSkills",
		const char* desc = "PlayerKernel(PlayerSkills) module");
	virtual ~PlayerSkills() {}

// Interface implementation
	virtual int Init(int argc, char** argv, int iTask);

	// These are overloaded from PlayerKernel
	virtual void OnInit(RealSide realSide, int uniform, PlayMode mode);
	virtual void OnHear(int time, float direction, bool ourTeam, int uniform, const char* msg);

// Operations
	/// Inertia compensation
	float CompMoment(float) const;
	/// Turn compensating inertia
	float CompTurn(float) const;

	/// How many steps do we need to run given distance
	int PredictSteps(float fDist, float fPower, float fActSpeed = 0) const;

	/// View angle depending on distance
	ViewWidth WidthFromDistance(float) const;
	/// Dash power according to current stamina mode
	float RecommDashPower(bool bFast) const;

	void SetPlayerRole(PlayerRole role) { m_PlayerRole = role; }
	PlayerRole GetPlayerRole() const { return m_PlayerRole; }

protected:
	bool IsBallKickAble() const { return m_bKickable; }

	/// Making decisions
	virtual void Act();

	/// Turn while scanning for ball or for anything else.
	float Scan();
	
	/// Kick to goal
//	void KickToGoal();
	/// Kick to goal
	void KickToGoal2();
	/// Better kick to goal
	void KickToGoal3();
	
//--- Ball interception routine ---

	/// Results of ball path simulation
	class CatchSimData;

	/// Is it possible to kick the ball in? (Should we even think about it,
	/// based on current play mode?)
	bool PlayerSkills::SomeoneShouldKickIn();
	/// Should we kick the ball in when it is not PlayOn?
	virtual bool ShouldKickIn();
	/// Intercept the ball if possible. Return false if impossible.
	bool InterceptBall();
	/// Find out if we can intercept the ball
	bool CanInterceptBall(Point* point);

	/// Helper function for CanInterceptBall - simulates ball path
	void CatchSimBallPath(List<CatchSimData> * output);
	/// Helper function for CanInterceptBall - simulates one player in next cycle
	void CatchSimRunningPlayer(float dashPower, float* speed, float* distance);
	/// Helper function for CanInterceptBall - evaluates simulation data
	bool CatchEvaluateData(Point* point, List<CatchSimData> * input);

#ifdef USE_OLD_INTERCEPT
	/// Run to ball (used by goalie and RunToBall3)
	void RunToBall2();
	/// Run to ball (used by player when catching a pass)
	void RunToBall3();
	// Should I run after the ball?
	bool DependentForBall() const;
	/// Get our nearest player to the ball; -1 -> this player
	int NearFriend(int* pCycles) const;
	/// Get opponent nearest player to the ball
	int NearEnemy(int* pCycles) const;
#endif // USE_OLD_INTERCEPT
	/// Is given point between points p1 and p2?
	bool InTheMiddle(const Point& tested, const Point& p1, const Point& p2) const;

//---

	/// Run to a position
	void RunToPoint(const Point& target, bool hurry, bool forLife = false, float posTol = POS_TOL, int angTol = 10);
	/// Run to a position backwards (for goalie)
	void RunToPointBackwards(const Point& target, bool hurry, bool forLife = false, float posTol = POS_TOL, int angTol = 10);
    // GP
    /// Run to a position (formation version)
	void RunToPos(const Point&);

	/// First dribbling
	void DribbleTo(const Point&);
	/// Second dribling
	void DribbleTo2(const Point&, float angle = 0);

	/// Dumb kick
	void DumbKick(const Point&);

	/// Turn body to some point
	void TurnTo(const Point&);
	/// Move to some point
	void MoveTo(const Point&);
	/// Change view
	void SetView(const ViewWidth);

	/// Catch the ball
	void CatchBall();
	/// Are we able to catch the ball?
	bool CanCatchBall() const;

	/// Tackle
	void Tackle(const float);
	/// Are we able to tackle the ball?
	bool CanTackleBall() const;

	/// Send parameters
	bool ShouldSendInfo();
	void SendInfo();

	/// Turn ball around
	void TurnBall();

	/// Pass to a given place
	void PassBallTo(const Point& pos, float fRem_spd = 0.7f);
	/// Pass to a player
	void PassBallToPlayer(const Player& player, float spd = 0.7f);

	/// Turn neck to some point
	void TurnNeckTo(const Point& future_pos, const Point& future_mypos,
		float fNextTurn = 0);
	/// Align neck with body
	void AlignNeck();

	/// Predict speed in next step
	Vector PredictNextVel(float DashPower) const;

	virtual void BehaveWithBall() {}
	virtual void BehaveWithoutBall() {}
	virtual void BehaveWithBallGoalie() {}
	virtual void BehaveWithoutBallGoalie() {}
#ifdef GOALIE
	virtual void BehaveWithoutBallKnowledgeGoalie() {}
#endif

	/// Find out position before kick off
	virtual Point GetHomePos() { return Point(); }

    // GP
	/// Return offside line position
	float GetOffsideLine() const;

	PlayerRole m_PlayerRole;
	int m_iGoalieCatchBan;

private:
	/// Command generator
	CommandsInterface* m_pCommandGen;

	/// Vector between ball and player
	Vector m_BallDiff;
	/// Distance between ball and player (does not have to be the same as m_BallDiff!)
	float m_fBallDistance;
	/// Can we kick ball?
	bool m_bKickable;

	/// Last time when we turned neck
	int m_iTimeOfLTurnNeck;

	/// Making decisions while play_on
	void RunPlayOn();
	/// Making decisions while not play_on (time is not running)
	void RunPlayOff();

	/// Kick to a place in next simulation step
	void NearKick(const Point&);

	/// Auxiliary method for dribbling
	bool DribbleRun(float);

protected:
	/// Structure that contains differences between all seen 
	/// players and the ball
	class CatchSimData
	{
	private:
		float myDif;
		int friendCnt;
		float * friendDifs;
		int enemyCnt;
		float * enemyDifs;

	public:
		inline CatchSimData(int fc, int ec);
		~CatchSimData() { free(friendDifs); free(enemyDifs); }

		int GetFriendCnt() { return friendCnt; }
		int GetEnemyCnt() { return enemyCnt; }

		float GetMyDif() { return myDif; }
		void SetMyDif(float d) { myDif = d; }
		float GetFriendDif(int i) { return friendDifs[i]; }
		void SetFriendDif(int i, float d) { friendDifs[i] = d; }
		float GetEnemyDif(int i) { return enemyDifs[i]; }
		void SetEnemyDif(int i, float d) { enemyDifs[i] = d; }
		
		Point ballPos;

	};

};

PlayerSkills::CatchSimData::CatchSimData(int fc, int ec)
{
	friendCnt = fc; enemyCnt = ec;
	friendDifs = (float*) malloc(sizeof(float) * fc);
	enemyDifs = (float*) malloc(sizeof(float) * ec);
}

#endif // MODULES_PLAYERSKILLS_H
