#ifndef AIM_BOT_HEADER
#define AIM_BOT_HEADER
#include "client.h" // MAX_TARGET_SPOTS...
#include "engine/r_studioint.h"
#include "engine/studio.h"
using namespace std;

//=======================================================================================
class AimingRandomizer
{
public:
	AimingRandomizer();
	void next();

	float h;
	float f;
	float r;

protected:
	float fraction; // 0 <= fraction <= 1

	float rad_from;
	float az_from;
	float el_from;

	float rad_to;
	float az_to;
	float el_to;

	float rad; // radius
	float az;  // azimuth
	float el;  // elevation

};

//=======================================================================================
struct aimvec
{
	float h;
	float f;
	float r;
};

//=======================================================================================
bool pathFree(float* from,float* to);
bool IsAimingAtMe( int ax );

//=======================================================================================
class OriginAimbot
{
public:
	// updates "target" index
	virtual void findTarget();

	// main aimbot function. recalculates view angles. see below
	virtual void CalcViewAngles();
    
	// these values are calculated by CalcViewAngles()
	vec3_t aim_viewangles, aim_spot;

	// Aim Vector Standing
	vector<aimvec> AimVecsS;

	// Aim Vector Ducking
	vector<aimvec> AimVecsD;

	// Draw aiming vectors
	virtual void draw();

	// Current Target we are aiming at.. FIXME: make it protected
	int target; // =-1

	// first aim spot FIXME: make me private
	int firstaimspot;

	// returns approximate fov angle (absolute value)
	virtual void calcFovangleAndVisibility(int ax);

protected:
	virtual void    CalcVec_MeToTarget( float* out );
	virtual void    CalcTargetSpot    ( float *out );
	virtual aimvec* TargetRegion      ( int ax );
	virtual void     draw_player_vecs ( int ax );

	AimingRandomizer randomizer;

	virtual double GetAimingFov (int ax);
	virtual bool   GetPlayerVisX(int ax){ return (cvar.aimthru || vPlayers[ax].visible); }
	virtual bool   GetAimingTeam(int ax)
	{
		if (cvar.team<=0 && (me.team != vPlayers[ax].team)) return true; 
		if (cvar.team==1) return true;
		if (cvar.team>1 &&  (me.team == vPlayers[ax].team)) return true; 
		return false;
	}

public:
	OriginAimbot() : target(-1), firstaimspot(0) {}
	virtual ~OriginAimbot(){}
};

class BoneAimbot
	:public OriginAimbot
{
	//
	// This class intercepts the StudioDrawPlayer call 
	// and updates vPlayer target spots, but only for the currently
	// targeted player ( this->target )
	// it also assists in team detection by providing a model
	// based team detection. 
	//
public:
	virtual void command();

	// draw aiming info according to avdraw. call this in hud_redraw
	virtual void draw();

	virtual void save(const char* filename);
	virtual void load(const char* filename);

    // updates vPlayer target spots for current target
	virtual void PostStudioDrawPlayer( int flags, struct entity_state_s *pplayer );

    // used for avdraw 3 type. selects which bone to highlight. used for editing.
	int my_curSelectedBone; 
	
protected:
	struct ModelAimSpot
	{
		ModelAimSpot() : boneindex(0), boneindex2(0), factor2(0.5) {}

		int    boneindex;  // bone to aim at
		int    boneindex2; // if boneindex2 != 0, we are using 2-bone based aiming
		float  factor2;    // scale factor for bone1->bone2 vector

		//vec3_t offset;     // optional offset
	};

	struct ModelInfo
	{
		ModelInfo() : team(0), numAimspots(0){}

		int    numAimspots;
		ModelAimSpot aimspots[MAX_TARGET_SPOTS];

		int    team;
		string name;
	};

	typedef std::map< std::string, ModelInfo > HashToInfoMap;
	typedef HashToInfoMap::iterator iterator;

    // used to map a model hash to a ModelInfo
	HashToInfoMap hashToInfo;

	// model info currently active (targeted) 
	struct ModelInfo* my_curModelInfo;

	// optional offset for first aim spot only (head)
	aimvec offset_first;

	// returns NULL if not found, creates if cretenew set.
	virtual ModelInfo* getModelInfo(const char* arg_name);

	void init()
	{
		target = -1;
		my_curSelectedBone = 0;
		my_curModelInfo = NULL;
		offset_first.f=offset_first.h=offset_first.r=0;
	}

	// origin aimbot hook. calculates a better target spot if data available
	virtual void CalcTargetSpot(float *out);
	virtual void ModelBasedAim (float* out);

public:
	BoneAimbot() {init();}

};

extern BoneAimbot gAimbot;

#endif
