#include "hud.h"
#include "parsemsg.h"
#include "const.h"
#include "cl_util.h"
#include "r_efx.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "event_api.h"
#include "triangleapi.h"
#include "math.h"

extern vec3_t v_angles,v_origin;
// Used for cam
extern vec3_t camera_offset;
extern vec3_t g_CamAngles;
extern int cam_thirdperson;
extern cvar_t *cam_idealdist;

DECLARE_MESSAGE(m_MeleeTarget, TMelee);
DECLARE_MESSAGE(m_MeleeTarget, DeTMelee);

int CHudMeleeTarget::Init(void)
{	
	HOOK_MESSAGE(TMelee);
	HOOK_MESSAGE(DeTMelee);
	
	Reset();

	gHUD.AddHudElem(this);
	m_iFlags |= HUD_ACTIVE;
	return 1;
}

void CHudMeleeTarget::Reset(void)
{
	m_blTargeted = false;
	m_iTargetedIndex = -1;
}

int CHudMeleeTarget::VidInit(void)
{	
	m_HUD_MeleeTarget = gHUD.GetSpriteIndex( "meleetarget" );
	m_MeleeTargetSize = &gHUD.GetSpriteRect(m_HUD_MeleeTarget);

	return 1;
}

vec3_t CHudMeleeTarget::GetCamPos()
{
	vec3_t camAngles = g_CamAngles;
	vec3_t camForward, camRight, camUp;
	//calculate camera pos
	pmtrace_t tr;
	AngleVectors( camAngles, camForward, camRight, camUp );
	cl_entity_t *player = gEngfuncs.GetLocalPlayer();
	if ( (player && (gEngfuncs.GetMaxClients() > 0) && (gViewPort && gEngfuncs.pEventAPI)) && cam_thirdperson)
	{	
		vec3_t view_ofs;
		gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );

		vec3_t player_origin = player->origin + view_ofs;
		vec3_t camera_origin = player_origin  + camera_offset - camForward * (cam_idealdist->value + 16);
		
		//check if something blocks our view
		gEngfuncs.pEventAPI->EV_SetSolidPlayers(player->index - 1);
		gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
		gEngfuncs.pEventAPI->EV_PlayerTrace( player_origin, camera_origin, PM_NORMAL, -1, &tr );
		float dist = cam_idealdist->value * tr.fraction; //update the view distance
		return player_origin  + camera_offset - camForward * (dist + 16);

	}
	else
	{
		return player->origin;
	}

}

bool CHudMeleeTarget::InViewCone ( vec3_t vecOrigin )
{
	Vector	vecLOS, camForward;
	float	flDot;
	AngleVectors( g_CamAngles, camForward, NULL, NULL );

	vec3_t vecLocalOrigin = GetCamPos();

	vecLOS = vecOrigin - vecLocalOrigin;
	vecLOS = vecLOS.Normalize();

	flDot = DotProduct (vecLOS, camForward);

	if ( flDot > -0.3 )
	{
		return true;
	}
	else
	{
		return false;
	}
}

int CHudMeleeTarget::Draw(float fltime)
{	if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ))
	{	return 1;
	}

	if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
	{	return 1;
	}

	if (!m_blTargeted || m_iTargetedIndex == -1)
	{	return 1;
	}
	
	// Make sure player is valid
	cl_entity_t *pPlayer = gEngfuncs.GetEntityByIndex(m_iTargetedIndex);
	if ( !pPlayer )
	{	return 1;
	}

	// Make sure this guy is in your view...
	if(!InViewCone(pPlayer->origin))
	{	return 1;
	}

	cl_entity_t *pLocal = gEngfuncs.GetLocalPlayer();

	// If we cant make a clear traceline to the targeted, dont draw him on the hud
	pmtrace_t tr;
	tr = *(gEngfuncs.PM_TraceLine((float *)&pLocal->origin, (float *)&pPlayer->origin , PM_TRACELINE_PHYSENTSONLY ,2, -1));
	
	// We cant see him, dont draw him on the hud!
	if(tr.fraction >= 1.0)
	{
		//draw Melee Target
		vec3_t screen;
		gEngfuncs.pTriAPI->WorldToScreen(pPlayer->origin,screen);
		int width = m_MeleeTargetSize->right - m_MeleeTargetSize->left;
		int height = m_MeleeTargetSize->bottom - m_MeleeTargetSize->top;
		SPR_Set(gHUD.GetSprite(m_HUD_MeleeTarget), 255, 0, 0);
		SPR_DrawAdditive( 0, XPROJECT(screen.x)-width/2, YPROJECT(screen.y)-height/2, m_MeleeTargetSize );
	}
	
	return 1;
}

int CHudMeleeTarget::MsgFunc_TMelee( const char *pszName, int iSize, void *pbuf )
{
	BEGIN_READ( pbuf, iSize );
	int iIndex = READ_BYTE();
	m_iTargetedIndex = iIndex;
	m_blTargeted = true;

	return 1;
}

int CHudMeleeTarget::MsgFunc_DeTMelee( const char *pszName, int iSize, void *pbuf )
{
	BEGIN_READ( pbuf, iSize );
	m_iTargetedIndex = -1;
	m_blTargeted = false;

	return 1;
}
