#ifndef BTASK_H
#define BTASK_H
#include "../bot/bot_types.h"

#define LOST_TOO_LONG 500

/* NOTES:
	the only way to get to FireBeam should be from a ChargeBeam state
*/
typedef enum 
{
	btNone = 0,
	btFollowBuddy,
	btFollowChargeBeam,
	btFireBeam,
	btFireKiBlast,
	btPowerUp
	
} BuddyTaskCode;

typedef enum
{
	bsPlayers = 1,
	bsBuddies = 2,
	bsAttacks = 4
} EBuddySense;

typedef enum
{
	tsComplete,
	tsCantSwitch,
	tsCanSwitch,
	tsRunNow
} EBuddyTaskState;

class CBuddyTask
{
public:
	// member variabeles
	float Delay;
	EBuddyTaskState TaskState;	
	EBuddySense m_eSense;

	CBuddyTask() { TaskState = tsComplete; };

	virtual ~CBuddyTask(void) { return; }; // destructor

	// member functions
	//float GetTaskDelay(void)						{ return Delay; };
	EBuddyTaskState GetTaskState(void)		{ return TaskState; };

	// if this returns a valid Buddy Task then we delete our current
	// buddy task and create this one
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy) = 0;
	
	virtual BuddyTaskCode TaskIdentify(void) = 0;
	
	// this will find enemies and possibly change our priorities
	//
	// returns the threat level
	long SenseThreat(CBuddy* pBuddy);
	
	// this will take our threat calculation and decide if a task change
	// is required or if the current task can handle it
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy) = 0;

	// maybe we're swapping out of a attack mode and have to destroy the attack
	virtual void CleanUp(CBuddy* pBuddy) = 0;

	// print any debug info
	virtual void DebugPrint(CBuddy *pBuddy) = 0;
};

/*
	This class handles just following your owner

	if danger is sensed depending on the buddy setting of the owner the buddy may switch to an attack
*/
class CBuddyTask_Follow : public CBuddyTask
{
public:
	~CBuddyTask_Follow();
	CBuddyTask_Follow();

	virtual BuddyTaskCode TaskIdentify() { return btFollowBuddy; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy);
	virtual void CleanUp(CBuddy* pBuddy) { return; };
	CBuddyTask* AttackThink(CBasePlayer *pBuddyOwner);
	void SetAttack(BOOL attack) { bAttack = attack; };
	virtual void DebugPrint(CBuddy *pBuddy);
protected:
	BOOL bAttack;
	Vector lastPos;
	int lostCt;
	BOOL bShouldMove;
};

/*
	We are following our buddy and charging (uses nested states)
*/
class CBuddyTask_Follow_BeamCharge : public CBuddyTask
{
public:
	CBuddyTask_Follow_BeamCharge();
	~CBuddyTask_Follow_BeamCharge();
	
	virtual BuddyTaskCode TaskIdentify() { return btFollowChargeBeam; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy);
	virtual void CleanUp(CBuddy* pBuddy) { return; };
	virtual void DebugPrint(CBuddy *pBuddy);

};

class CBuddyTask_BeamFire : public CBuddyTask
{
public:
	CBuddyTask_BeamFire();
	~CBuddyTask_BeamFire();
	
	virtual BuddyTaskCode TaskIdentify() { return btFireBeam; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy);
	virtual void CleanUp(CBuddy* pBuddy);
	void SetEnemy(EHANDLE enemy) { m_pEnemy = enemy; };
	virtual void DebugPrint(CBuddy *pBuddy);

protected:
	bool bOneThought; // we need at least one thought
	EHANDLE m_pEnemy;
};

/*
	Task Description:
		This task should only fire a kiblast and return to default buddy mood state
*/
class CBuddyTask_KiBlastFire : public CBuddyTask
{
public:
	CBuddyTask_KiBlastFire();
	~CBuddyTask_KiBlastFire();
	
	virtual BuddyTaskCode TaskIdentify() { return btFireKiBlast; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy);
	virtual void CleanUp(CBuddy* pBuddy) { return; };
	void SetEnemy(EHANDLE enemy) { m_pEnemy = enemy; };
	virtual void DebugPrint(CBuddy *pBuddy);

protected:
	bool bOneThought; // we need at least one thought
	EHANDLE m_pEnemy;
};

class CBuddyTask_HomeThroughMap : public CBuddyTask
{
public:
	CBuddyTask_HomeThroughMap();
	~CBuddyTask_HomeThroughMap();
	
	virtual BuddyTaskCode TaskIdentify() { return btFireKiBlast; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy *pBuddy);
	virtual void CleanUp(CBuddy* pBuddy) { return; };
	void HomeThroughMap(CBuddy *pBuddy);
	void CheckUpDown(CBuddy *pBuddy);
	void AvoidNearFriends(CBuddy *pBuddy);
	void CheckFOV(CBuddy *pBuddy);
	void CheckSkybox(CBuddy *pBuddy);
	void TurnAtWall(Vector *vecPlaneNormal, CBuddy *pBuddy);
	void TurnAround(CBuddy *pBuddy);
	virtual void DebugPrint(CBuddy *pBuddy);

protected:
	Vector m_vIdealLookAngles;
	float m_fCheckUpDownTime;
	float m_fDontAvoidWallTime;
	float m_fLookDelay;
	float m_fAvoidFriendsDelay;
};

/*
	Task Description:
		This task handles powering up
*/
class CBuddyTask_PowerUp : public CBuddyTask
{
public:
	CBuddyTask_PowerUp();
	~CBuddyTask_PowerUp();
	
	virtual BuddyTaskCode TaskIdentify() { return btPowerUp; };
	virtual CBuddyTask* TaskThink(CBuddy *pBuddy);
	virtual CBuddyTask* ManageThreat(CBuddy* pBuddy);
	virtual void CleanUp(CBuddy* pBuddy) { return; };
	virtual void DebugPrint(CBuddy *pBuddy);

protected:
	bool bPowerUpStarted; 
};

#endif

