//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Utility code.
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "hl2wars/util_hl2wars_shared.h"
#include "engine/IVDebugOverlay.h"
#include "hl2wars/rts_shareddefs.h"
#include "hl2wars/rts_tracefilter.h"
#include "collisionutils.h"

#ifdef CLIENT_DLL
#include "c_ai_basenpc.h"
#else
#include "ai_basenpc.h"
#endif

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

#define C_HL2Wars_Player CHL2Wars_Player

ConVar g_debug_building( "g_debug_building", "0", FCVAR_CHEAT|FCVAR_REPLICATED );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CheckLineBetweenPoints( Vector point1, Vector point2 )
{
	trace_t tr;
    UTIL_TraceLine(point1,point2, MASK_SOLID, NULL, COLLISION_GROUP_NONE,&tr);

	// traceline for debugging
	if( g_debug_building.GetBool() )
		debugoverlay->AddLineOverlay( point1,point2, 100, 55, 255, false, 0.2 ); 

	// hit ground?
    if ( tr.DidHitWorld() || tr.IsDispSurface())
    {
  	  return true;
    }	

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Checks if the npc is the real box
// I suppose this could be done in a cleaner way
//-----------------------------------------------------------------------------
#ifdef CLIENT_DLL
	bool CheckNPCInRealBox( Vector origin, QAngle angle, Vector mins, Vector maxs, C_AI_BaseNPC *pNPC )
#else
	bool CheckNPCInRealBox( Vector origin, QAngle angle, Vector mins, Vector maxs, CAI_BaseNPC *pNPC )
#endif
{
	Vector transformedOrigin;
	transformedOrigin = pNPC->GetAbsOrigin() - origin;
	VectorYawRotate( transformedOrigin, -1 * angle[YAW], transformedOrigin );
	if( IsPointInBox( transformedOrigin,  mins, maxs ) )
		return true;
	
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Checks wheter we can place this building here
//-----------------------------------------------------------------------------
bool UTIL_ValidBuildingPosition( Vector origin, QAngle angle, Vector mins, Vector maxs, float tolerance, bool ignorefriendly, int teamid )
{
	Vector point1, point2, point3, point4;
	point1[2] = point2[2] = point3[2] = point4[2] = origin.z /*- ((mins[2] + maxs[2])/2.0f)*/ + tolerance;

	point1[0] = mins[0];
	point1[1] = mins[1];
	point2[0] = mins[0];
	point2[1] = maxs[1];
	point3[0] = maxs[0];
	point3[1] = maxs[1];
	point4[0] = maxs[0];
	point4[1] = mins[1];

	VectorYawRotate( point1, angle[YAW], point1 );
	VectorYawRotate( point2, angle[YAW], point2 );
	VectorYawRotate( point3, angle[YAW], point3 );
	VectorYawRotate( point4, angle[YAW], point4 );

	point1[0] += origin[0];
	point1[1] += origin[1];

	point2[0] += origin[0];
	point2[1] += origin[1];

	point3[0] += origin[0];
	point3[1] += origin[1];

	point4[0] += origin[0];
	point4[1] += origin[1];

	// check the ground
	if( CheckLineBetweenPoints( point1, point2 ) )
		return false;

	if( CheckLineBetweenPoints( point2, point3 ) )
		return false;

	if( CheckLineBetweenPoints( point3, point4 ) )
		return false;

	if( CheckLineBetweenPoints( point4, point1 ) )
		return false;

	if( CheckLineBetweenPoints( point1, point3 ) )
		return false;

	if( CheckLineBetweenPoints( point2, point4 ) )
		return false;

	// now check npc's
	CBaseEntity *entityList[64];
	int boxCount = UTIL_EntitiesInBox( entityList, ARRAYSIZE(entityList), mins*2 + origin, maxs*2 + origin, /*FL_NPC*/ 0 );
	/*	#ifdef CLIENT_DLL
	Msg("Count client: %d, array size %d\n", boxCount, ARRAYSIZE(entityList));
		#else
	Msg("Count server: %d, array size %d\n", boxCount, ARRAYSIZE(entityList));
		#endif*/
	while ( boxCount > 0 )
	{
		boxCount--;
		#ifdef CLIENT_DLL
			C_AI_BaseNPC *pNPC = entityList[boxCount]->MyNPCPointer();
		#else
			CAI_BaseNPC *pNPC = entityList[boxCount]->MyNPCPointer();
		#endif
		if( pNPC )
		{
			if( !CheckNPCInRealBox( origin, angle, mins, maxs, pNPC ) )
				continue;

			if( !ignorefriendly )
				return false;

			if( pNPC->GetTeamRTSID() != teamid )
				return false;
		}
	}

	return true;
}

bool UTIL_IsValidTeam( int team_id, bool default_teams )
{
	if( default_teams )
	{
		if( team_id < 0 || team_id >= ( MAX_TEAMS_ID_RTS + DEFAULT_TEAMS) )
			return false;
	}
	else
	{
		if( team_id < DEFAULT_TEAMS || team_id >= ( MAX_TEAMS_ID_RTS + DEFAULT_TEAMS) )
			return false;
	}

	return true;
}

bool UTIL_IsRTSClientBrush( CBaseEntity *pEntity )
{
	#ifndef CLIENT_DLL
		CRTSClientBrush *pRTSClientBrush = dynamic_cast<CRTSClientBrush *>(pEntity);
		return pRTSClientBrush ? true : false;
	#else
		C_RTSClientBrush *pRTSClientBrush = dynamic_cast<C_RTSClientBrush *>(pEntity);
		return pRTSClientBrush ? true : false;
	#endif
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Simply trace the ground and store the position and normal
//-----------------------------------------------------------------------------
void UTIL_MouseGroundPos( Vector &origin, Vector &direction, CBaseEntity *ignore, Vector *position, Vector *normal ) 
{
	if( !position || !normal )
		return;

	// Check if the mouse points to a npc, if so, return the npc
    trace_t tr;

	CTraceFilterRTS TraceFiler( ignore );
	CTraceFilterRTS *pTraceFiler = &TraceFiler;

    UTIL_TraceLine(origin,origin + (direction *  8192), MASK_SOLID, pTraceFiler,&tr);
	
	// hit ground?
    if ( tr.DidHitWorld() || tr.IsDispSurface())//If we hit the ground, return the position
    {
		VectorCopy( tr.plane.normal, *normal );	// store normal
  	    VectorCopy( tr.endpos, *position );	// store position
    }
	else if( tr.m_pEnt ) {
		VectorCopy( tr.plane.normal, *normal );	// store normal
  	    VectorCopy( tr.endpos, *position );	// store position
	}
}

//-----------------------------------------------------------------------------
// Purpose: Calculate the direction between two points
// Output : 
//-----------------------------------------------------------------------------
#define PI 3.14159265359
QAngle UTIL_CalculateDirection( Vector point1, Vector point2 )
{
	float diff_x = point1.x - point2.x;
	float diff_y = point1.y - point2.y;
	float angle = atan( diff_y / diff_x ) * ( 180 / PI );

	// fix up angle if needed
	if( diff_x > 0 && diff_y > 0 )
		angle += 180.0f;
	else if( diff_x > 0 )
		angle += 180.0f;
	
	QAngle temp;
	temp[0] = temp[2] = 0.0f;
	temp[YAW] = angle;
	return temp;
}