//#define _CRTDBG_MAP_ALLOC
//#include <stdlib.h>
//#include <crtdbg.h>

#include "hud.h"
#include "parsemsg.h"
#include "cl_util.h"
#include "pm_defs.h"
#include "vgui_int.h"
#include "vgui_TeamFortressViewport.h"
#include "vgui_scouterstats.h"
// added by Pcjoe
#include "event_api.h"

#include <string.h>
#include <stdio.h>

#define RADAR_RADIUS 2000.0
#define XRADARCENTER_640 110
#define YRADARCENTER_640  60
#define RADARRADIUS_640	  40
#define XRADARCENTER_320  55
#define YRADARCENTER_320  30
#define RADARRADIUS_320	  20
#define	MAX_RELATIVE_VISIBLE_POWERLEVEL 0.1

enum {SCOUTER_OFF=0,SCOUTER_AUTO=1};//,SCOUTER_MAP=2,SCOUTER_PL=3};

DECLARE_COMMAND(m_Scouter, ToggleScouter);
DECLARE_COMMAND(m_Scouter, ShowMemLeaks);
DECLARE_MESSAGE(m_Scouter, DBEnt);

extern vec3_t v_angles,v_origin; 
extern char *sTFClassSelection[];
/* removed by DragonDude - replaced by sLocalisedScoreboardClassnames for this purpose
extern char *sLocalisedClasses[];
*/
extern char *sLocalisedScoreboardClassNames[];

extern int	g_IsSpectator[MAX_PLAYERS+1];

extern buddy_info_t gBuddyInfo[MAX_PLAYERS];

int CHudScouter::Init(void)
{	HOOK_COMMAND("scouter",ToggleScouter);
	HOOK_COMMAND("memoryleaks",ShowMemLeaks);

	HOOK_MESSAGE(DBEnt);

	m_iRadarFrame = 0;
	int n=0;
	for (n=0;n<MAX_PLAYERS+1;n++)
	{	m_fDrawPlayerDot[n] = false;
	}
	for (n=0;n<7;n++)
	{	m_iDragonBallEnt[n] = 0;
	}
	m_iStatsEnt = 0;
	m_bIsBuddy = false;
	m_flTimeDifference = 0;
	m_flDrawTime = 0;
	m_fScouter = false;
	m_flPlayerStatsTime = 4;

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

void CHudScouter::Reset()
{
	m_flLastStats = 0;
}

int CHudScouter::VidInit(void)
{	char buffer[255];
	int i=0;
	for(i=0;i<3;i++)
	{	sprintf(buffer,"scoutermetalmode%d",i+1);
		m_HUD_scoutermetalmode[i] = gHUD.GetSpriteIndex( buffer );
	}
	m_HUD_radarglass = gHUD.GetSpriteIndex( "radarglass" );
	m_HUD_scouterglass = gHUD.GetSpriteIndex("scouterglass");
	m_HUD_dragonballdot = gHUD.GetSpriteIndex( "dragonballdot");
	m_HUD_radarcenter = gHUD.GetSpriteIndex("radarcenter");
	char dot[255];
	for (i=0;i<7;i++)
	{	sprintf(dot,"dot%d",i+1);
		m_HUD_radardot[i] = gHUD.GetSpriteIndex(dot);
	}
	for (i=1;i<PC_RANDOM;i++)
	{	m_HUD_class[i] = gHUD.GetSpriteIndex(sTFClassSelection[i]);
	}	
	return 1;
}

int CHudScouter::Draw(float flTime)
{	if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ))
	{	gViewPort->m_pScouterStats->setVisible( false );
		return 1;
	}

	if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
	{	gViewPort->m_pScouterStats->setVisible( false );
		return 1;
	}

	SetTimeDifference(flTime);
	
	if (m_fScouter)
	{	int iScouterWidth = gHUD.GetSpriteRect(m_HUD_scoutermetal).right - gHUD.GetSpriteRect(m_HUD_scoutermetal).left;
		int iScouterHeight = gHUD.GetSpriteRect(m_HUD_scoutermetal).bottom - gHUD.GetSpriteRect(m_HUD_scoutermetal).top;
		int x = ScreenWidth - iScouterWidth;
		int y = ScreenHeight / 4;
		int r,g,b;
		UnpackRGB( r,g,b, RGB_WHITEISH );

		//draw scouter
		SPR_Set(gHUD.GetSprite(m_HUD_scoutermetal), r, g, b );		
		SPR_DrawHoles(0, x, y, &gHUD.GetSpriteRect(m_HUD_scoutermetal));
				
		DrawRadar(flTime,x,y);		
		gViewPort->m_pScouterStats->setVisible( true );
	}
	else
	{	//redraw radar pull down
		m_iRadarFrame = 0;
		gViewPort->m_pScouterStats->setVisible( false );
	}
	
	ResetTimeDifference( flTime );
	return 1;
}

void CHudScouter::DrawRadar(float flTime, int x, int y)
{	//draw radar glass
	int r,g,b;
	UnpackRGB( r,g,b, RGB_WHITEISH );
	SPR_Set(gHUD.GetSprite(m_HUD_radarglass), r, g, b );	
	SPR_DrawAdditive(m_iRadarFrame, x, y, &gHUD.GetSpriteRect(m_HUD_radarglass));

	if (m_iRadarFrame < SPR_Frames(gHUD.GetSprite(m_HUD_radarglass))-1 )
	{	if(flTime < m_flLastDraw || flTime - m_flLastDraw > 0.05)
		{	m_iRadarFrame++;
			m_flLastDraw = flTime;				
		}
		return;
	}

	//draw radar on scouter
	int iRadarWidth = gHUD.GetSpriteRect(m_HUD_radarglass).right - gHUD.GetSpriteRect(m_HUD_radarglass).left;
	int iRadarHeight = gHUD.GetSpriteRect(m_HUD_radarglass).bottom - gHUD.GetSpriteRect(m_HUD_radarglass).top;
		
	int iRadius;
	if (ScreenWidth < 640)
	{	x += XRADARCENTER_320;
		y += YRADARCENTER_320;
		iRadius = RADARRADIUS_320;
	}
	else
	{	x += XRADARCENTER_640;
		y += YRADARCENTER_640;
		iRadius = RADARRADIUS_640;
	}	
	DrawDragonRadar(flTime, x, y, iRadarHeight/2);
	DrawPlayerRadar(flTime, x, y, iRadarHeight/2);

	//draw center cross
	UnpackRGB( r,g,b, RGB_WHITEISH );
	SPR_Set(gHUD.GetSprite(m_HUD_radarcenter), r, g, b );
	int iWidth = gHUD.GetSpriteRect(m_HUD_radarcenter).right - gHUD.GetSpriteRect(m_HUD_radarcenter).left;
	int iHeight = gHUD.GetSpriteRect(m_HUD_radarcenter).bottom - gHUD.GetSpriteRect(m_HUD_radarcenter).top;	
	SPR_DrawHoles(0, x-iWidth*0.5, y-iHeight*0.5, &gHUD.GetSpriteRect(m_HUD_radarcenter));
}

void CHudScouter::DrawPlayerStats()
{	int iWidth = gHUD.GetSpriteRect(m_HUD_scouterglass).right - gHUD.GetSpriteRect(m_HUD_scouterglass).left;
	int iHeight = gHUD.GetSpriteRect(m_HUD_scouterglass).bottom - gHUD.GetSpriteRect(m_HUD_scouterglass).top;
	
	

	//draw empty glass
	int r,g,b;
	UnpackRGB( r,g,b, RGB_WHITEISH );
	//SPR_Set(gHUD.GetSprite(m_HUD_scouterglass), r, g, b );	
	//SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_radarglass));
	
	if(m_iStatsEnt)
	{	
		cl_entity_t *pClient=gEngfuncs.GetEntityByIndex(m_iStatsEnt);
		vec3_t screen;
		gEngfuncs.pTriAPI->WorldToScreen(pClient->origin,screen);
		int x = XPROJECT(screen.x)+15;
		int y = YPROJECT(screen.y)-15-iHeight;
		if(y<0)y=y+15;
		if(x>ScreenWidth - iWidth)x=x-15-iWidth;
		
		
		if ((m_bIsBuddy == false) && g_PlayerExtraInfo[m_iStatsEnt].playerclass!=PC_A18)
		{
			int iClassWidth =  gHUD.GetSpriteRect(m_HUD_class[1]).right - gHUD.GetSpriteRect(m_HUD_class[1]).left;
			int iClassHeight = gHUD.GetSpriteRect(m_HUD_class[1]).bottom - gHUD.GetSpriteRect(m_HUD_class[1]).top;

			//draw sprites of the class
			int iClassY = y + iHeight * 0.5 - iClassHeight * 0.5;
			int iClassX = x + iClassWidth;

			UnpackRGB( r,g,b, RGB_WHITEISH );
			SPR_Set(gHUD.GetSprite(m_HUD_class[g_PlayerExtraInfo[m_iStatsEnt].playerclass]), r, g, b );		
			SPR_DrawHoles(0, iClassX, iClassY, &gHUD.GetSpriteRect(m_HUD_class[g_PlayerExtraInfo[m_iStatsEnt].playerclass]) );
			
			//gViewPort->m_pScouterStats->setPos(x + iClassWidth * 2.5 , iClassY);
			gViewPort->m_pScouterStats->setPos(x + iClassWidth * 2.5 , iClassY);
			gViewPort->m_pScouterStats->setSize(iWidth - iClassWidth * 2.5, iClassHeight);
		
			//put stats in vgui panel
			gViewPort->m_pScouterStats->SetNameLabel(g_PlayerInfoList[m_iStatsEnt].name);
			gViewPort->m_pScouterStats->SetClassLabel(CHudTextMessage::BufferedLocaliseTextString( sLocalisedScoreboardClassNames[g_PlayerExtraInfo[m_iStatsEnt].scoreboardclass]));
			gViewPort->m_pScouterStats->SetPowerlevelLabel(g_PlayerExtraInfo[m_iStatsEnt].powerlevel);
			gViewPort->m_pScouterStats->setVisible(true);			
		}
		else
		{
			int iClassWidth =  gHUD.GetSpriteRect(m_HUD_class[1]).right - gHUD.GetSpriteRect(m_HUD_class[1]).left;
			int iClassHeight = gHUD.GetSpriteRect(m_HUD_class[1]).bottom - gHUD.GetSpriteRect(m_HUD_class[1]).top;

			//draw sprites of the class
			int iClassY = y + iHeight * 0.5 - iClassHeight * 0.5;
			int iClassX = x + iClassWidth;

			UnpackRGB( r,g,b, RGB_WHITEISH );
			SPR_Set(gHUD.GetSprite(m_HUD_class[g_PlayerExtraInfo[m_iStatsEnt].playerclass]), r, g, b );		
			SPR_DrawHoles(0, iClassX, iClassY, &gHUD.GetSpriteRect(m_HUD_class[g_PlayerExtraInfo[m_iStatsEnt].playerclass]) );

			gViewPort->m_pScouterStats->setPos(x + iClassWidth * 2.5 , iClassY);
			gViewPort->m_pScouterStats->setSize(iWidth - iClassWidth * 2.5, iClassHeight);
		
			//put stats in vgui panel
			gViewPort->m_pScouterStats->SetNameLabel(g_PlayerInfoList[m_iStatsEnt].name);
			gViewPort->m_pScouterStats->SetClassLabel(CHudTextMessage::BufferedLocaliseTextString( sLocalisedScoreboardClassNames[g_PlayerExtraInfo[m_iStatsEnt].scoreboardclass]));
			gViewPort->m_pScouterStats->SetPowerlevelLabel(gBuddyInfo[m_iStatsEnt].powerlevel);
			gViewPort->m_pScouterStats->setVisible(true);
		}
	}
	else
	{	gViewPort->m_pScouterStats->setVisible(false);
	}
}

void CHudScouter::DrawDot(Vector2D pos, int sprite, int color)
{
	int iWidth = gHUD.GetSpriteRect(sprite).right-gHUD.GetSpriteRect(sprite).left;
	int iHeight = gHUD.GetSpriteRect(sprite).bottom-gHUD.GetSpriteRect(sprite).top;

	int x = (int) (pos.x - iWidth*0.5);
	int y = (int) (pos.y - iHeight*0.5);
	
	int r,g,b;
	UnpackRGB( r,g,b, color);
	SPR_Set(gHUD.GetSprite(sprite), r, g, b );
	SPR_DrawHoles(0, x ,y, &gHUD.GetSpriteRect(sprite));
}

int CHudScouter::DrawDragonRadar(float flTime, int iMidX, int iMidY, int iRadius)
{	for (int n=0;n<7;n++)
	{	if (m_iDragonBallEnt[n])
		{	Vector2D vecDotPos;			
			if (!CalculateRadarPos(m_iDragonBallEnt[n], iMidX, iMidY, iRadius,vecDotPos))
			{	continue;
			}			
			//draw dragonball dots
			DrawDot(vecDotPos,m_HUD_dragonballdot,RGB_YELLOWISH);			
		}
	}
	return 1;
}

int CHudScouter::DrawPlayerRadar(float flTime, int iMidX, int iMidY, int iRadius)
{	cl_entity_t *player;
	player = gEngfuncs.GetLocalPlayer();
	int iOurPowerLevel= g_PlayerExtraInfo[player->index].powerlevel;
	if (iOurPowerLevel <= 0)
	{	return 0;
	}
	for (int n=1;n<MAX_PLAYERS;n++)
	{	//don't draw ourselves
		if ( n == player->index)
		{	continue;
		}
		
		//don't draw spectators
		if (g_IsSpectator[n])
		{	continue;
		}
		
		//don't draw players without a name
		if ( g_PlayerInfoList[n].name == NULL )
		{	continue;
		}

		int iHisPowerLevel = g_PlayerExtraInfo[n].powerlevel;
		if (iHisPowerLevel <= 0)
		{	continue;
		}
		
		if (g_PlayerExtraInfo[n].playerclass==PC_A18)
		{	continue;
		}
		//can't see this player, continue
		if ((float)iOurPowerLevel/(float)iHisPowerLevel < MAX_RELATIVE_VISIBLE_POWERLEVEL)
		{	continue;
		}

		//find out if the player holds a ball
		int fHoldsBall = false;
		for (int i=0;i<7;i++)
		{	if (n == m_iDragonBallEnt[i] )
			{	//player holds a dbal
				fHoldsBall = true;
				if(flTime < m_flLastDotDraw[n] || flTime - m_flLastDotDraw[n] > 0.5)
				{	//switch drawing on and of for this player
					m_flLastDotDraw[n] = flTime;
					m_fDrawPlayerDot[n] = !m_fDrawPlayerDot[n];
				}				
			}			
		}

		//don't draw it, this will be covered in the dragonball radar
		if (!m_fDrawPlayerDot[n] && fHoldsBall)
		{	continue;
		}

		//calculate the relative position of this player on the radar
		Vector2D vecDotPos;		
		if (!CalculateRadarPos(n, iMidX, iMidY, iRadius,vecDotPos))
		{	continue;
		}
		
		//calculate the size of the dot, according to his and your pl
		int size;
		if (ScreenWidth<640)
		{	if (iOurPowerLevel>iHisPowerLevel)
			{	size = 2 - (iOurPowerLevel/iHisPowerLevel) * 0.5;
				if (size<0)
				{	size = 0;
				}
			}
			else
			{	size = 1 + (iHisPowerLevel/iOurPowerLevel) * 0.5;
				if (size>3)
				{	size = 3;
				}
			}
		}
		else
		{	if (iOurPowerLevel>iHisPowerLevel)
			{	size = 4 - (iOurPowerLevel/iHisPowerLevel);
				if (size<0)
				{	size = 0;
				}
			}
			else
			{	size = 2 + (iHisPowerLevel/iOurPowerLevel);
				if (size>6)
				{	size = 6;
				}
			}
		}		
		
		//set the color of the dot, green for friends, red for enemies
		if(g_PlayerExtraInfo[n].teamnumber == g_iTeamNumber && g_iTeamNumber)
		{	DrawDot(vecDotPos,m_HUD_radardot[size],RGB_GREENISH);
			if(gBuddyInfo[n].buddy_index)
			{
				if (CalculateRadarPos(gBuddyInfo[n].buddy_index, iMidX, iMidY, iRadius,vecDotPos))
				{	DrawDot(vecDotPos,m_HUD_radardot[size],RGB_GREENISH);
				}
			}
		}
		else
		{	DrawDot(vecDotPos,m_HUD_radardot[size],RGB_REDISH );
			if(gBuddyInfo[n].buddy_index)
			{
				if (CalculateRadarPos(gBuddyInfo[n].buddy_index, iMidX, iMidY, iRadius,vecDotPos))
				{	DrawDot(vecDotPos,m_HUD_radardot[size],RGB_REDISH);
				}
			}
		}
	}

	if(gBuddyInfo[player->index].buddy_index)
	{
		Vector2D vecDotPos;		
		if (CalculateRadarPos(gBuddyInfo[player->index].buddy_index, iMidX, iMidY, iRadius,vecDotPos))
		{	DrawDot(vecDotPos,m_HUD_radardot[2],RGB_WHITEISH);
		}
	}

	return 1;
}

bool CHudScouter::CalculateRadarPos(int iClientindex, int iMidX, int iMidY, int iRadius, Vector2D &vecPos)
{	cl_entity_t *pClient;
	pClient = gEngfuncs.GetEntityByIndex( iClientindex );
	if (!pClient)
	{	return false;
	}
	
	vec3_t v_forward, v_right, v_up;
	AngleVectors( v_angles, v_forward, v_right, v_up);
	Vector2D vecPlayerOrigin = Vector2D(v_origin.x,v_origin.y);
	Vector2D vecEntityOrigin = Vector2D(pClient->origin.x, pClient->origin.y);
	float flDistance = (vecPlayerOrigin - vecEntityOrigin).Length();
	if (flDistance > RADAR_RADIUS)
	{	return false;
	}
	
	//calculate angle, compared to right vector
	Vector2D vecRight = Vector2D(v_right.x,v_right.y);
	Vector2D vecPlayerToEntity = vecEntityOrigin - vecPlayerOrigin;
	
	//calculate angle to right vector
	float flDotProduct = vecRight.x * vecPlayerToEntity.x + vecRight.y * vecPlayerToEntity.y;
	float flAngle = acos( flDotProduct/(vecPlayerToEntity.Length()*vecRight.Length()));

	//scale
	float flRadius = 0.5 * (float)iRadius * flDistance / RADAR_RADIUS;
				
	//calculate x and y on radar
	vecPos.x = iMidX + cos (flAngle) * flRadius;
	Vector2D vecForward = Vector2D(v_forward.x,v_forward.y);
	flDotProduct = vecForward.x * vecPlayerToEntity.x + vecForward.y * vecPlayerToEntity.y;
	if (flDotProduct>0)
	{	vecPos.y = iMidY - sin (flAngle) * flRadius;
	}
	else
	{	vecPos.y = iMidY + sin (flAngle) * flRadius;
	}
	return true;
}

void CHudScouter::UserCmd_ShowMemLeaks()
{	//_CrtDumpMemoryLeaks();
}

void CHudScouter::UserCmd_ToggleScouter()
{	/*
	m_iScouterMode++;
	if(m_iScouterMode>SCOUTER_PL)
	{	m_iScouterMode=SCOUTER_OFF;
	}
	if(m_iScouterMode==SCOUTER_PL)
	{	m_flPlayerStatsTime = 4;
	}
	else
	{	m_flPlayerStatsTime = 2;
	}
	*/
	m_fScouter = !m_fScouter;

	// Edited by Pcjoe - Mixing in with turbo/swoop sounds
	cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();
	if (!m_fScouter)
	{	gViewPort->m_pScouterStats->setVisible( false );
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_STREAM, "common/null.wav", 1, ATTN_NORM, 0, PITCH_NORM );
	}
	else 
	{	gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_STREAM, "weapons/scouter.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		m_HUD_scoutermetal=m_HUD_scoutermetalmode[1];//TODO: can use a sprite fix
	}	
}

int CHudScouter::MsgFunc_DBEnt(const char *pszName,  int iSize, void *pbuf )
{	BEGIN_READ( pbuf, iSize );
	char ball = READ_BYTE();
	short ent = READ_SHORT();
	m_iDragonBallEnt[ball] = ent;
	return 1;
}
