#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __TOOLS_LOS_H_
#define __TOOLS_LOS_H_

#include "Core/Asura_Hash.h"


class Tools_LOS
{
	public :
		//LOS tests will be limited to the current zone , unless puOutputZoneHash is supplied

		static bool FindPolyInLOS(const class Asura_Vector_3& alpha, const class Asura_Vector_3& beta,int& polyIndex,int& moduleIndex,float& distance,bool bIncludeAllPolys = false,Asura_Hash_ID* puOutputZoneHash = 0);
		static bool FindPolyInLOS(const class Asura_Vector_3& alpha, const class Asura_Vector_3& beta,int& polyIndex,int& moduleIndex,Asura_Hash_ID* puOutputZoneHash = 0);

		static bool FindPolyAndPositionUnderCursor(int& polyIndex,int& moduleIndex,Asura_Vector_3& position,Asura_Hash_ID* puOutputZoneHash = 0);
		static bool FindModuleUnderCursor(int& moduleIndex,Asura_Hash_ID* puOutputZoneHash = 0);


		static bool FindVertInLOS(const class Asura_Vector_3& alpha, const class Asura_Vector_3& beta,int& vertIndex,int& moduleIndex,bool (*pfnVertexFilter)(int iModuleIndex,int iVertexIndex)=0,bool bIncludeLooseVerts = false);
		static bool FindVertUnderCursor(int& vertIndex,int& moduleIndex,bool (*pfnVertexFilter)(int iModuleIndex,int iVertexIndex)=0,bool bIncludeLooseVerts = false);

		//If bAllowDiagonalInQuad then the edge selection will also pickup on edge that will be created when a quad
		//is eventually split into triangles
		static bool FindEdgeUnderCursor(struct Tools_LOS_EdgeOutput& xOutput, bool bAllowDiagonalInQuad = false);

		//LOS tests against the collision meshes (instead of Asura_Meshes)
		static bool FindCollModuleAndPositionUnderCursor(int& iModuleIndex,Asura_Vector_3& xPosition,Asura_Vector_3* pxOutputNormal,Asura_Hash_ID* puOutputZoneHash = 0);

        static void GetCursorLOSOriginAndDir( Asura_Vector_3* pxOrigin, Asura_Vector_3* pxDir );

		static void SetIgnoreTransparent(bool bIgnore){s_bIgnoreTransparent = bIgnore;}
		//sets LOS test to ignore back face culling
		static void SetIgnoreBFC(bool bIgnore){s_bIgnoreBFC = bIgnore;}

		//Set LOS to ignore polygons that have these flags
		//Note that generally DontRender polygons will be ignored regardless , since
		//the LOS test will only hit polygons that are being rendered unless bIncludeAllPolys is used
		static void SetPolygonFlagsToIgnore(u_int uFlags){s_uPolygonFlagsToIgnore = uFlags;}

		//Disable module linking checks. (Automatically ignored if bIncludeAllPolys is used in LOS tests)
		static void SetIgnoreModuleLinking(bool bIgnore){s_bIgnoreModuleLinking = bIgnore;}

		//sets an optional callback functioning for skipping modules from the LOS test.
		//The callback should return true if the module should be tested.
		static void SetModuleFilterCallback(bool (*pfnModuleFilterCallback)(int iModuleIndex)) {s_pfnModuleFilterCallback = pfnModuleFilterCallback;}

	private :
		static bool FindPolyInLOSInCurrentZone(const class Asura_Vector_3& alpha, const class Asura_Vector_3& beta,int& polyIndex,int& moduleIndex,float& fOutputDistance,float fDistanceToCheck,bool bIncludeAllPolys);

		static bool FindCollModuleInLOS(const Asura_Vector_3& xAlpha, const Asura_Vector_3& xBeta,int& iModuleIndex,float& fOutputDistance,Asura_Vector_3* pxOutputNormal,bool bIncludeAllPolys,Asura_Hash_ID* puOutputZoneHash);
		static bool FindCollModuleInLOSInCurrentZone(const class Asura_Vector_3& xAlpha, const class Asura_Vector_3& xBeta,int& iModuleIndex,float& fOutputDistance,Asura_Vector_3* pxOutputNormal,float fDistanceToCheck,bool bIncludeAllPolys);

		static bool FindLooseVertexInLOS(const class Asura_Vector_3& alpha, const class Asura_Vector_3& beta,float fMaxDistance,int& iVertexIndex,int& iModuleIndex);

		static bool s_bIgnoreTransparent;
		static bool s_bIgnoreBFC;
		static u_int s_uPolygonFlagsToIgnore;
		static bool s_bIgnoreModuleLinking;

		static bool (*s_pfnModuleFilterCallback)(int iModuleIndex);
	
};

struct Tools_LOS_Edge
{
	int m_iModuleIndex;
	int m_iPolygonIndex;
	int m_aiVertexIndex[2];
};

struct Tools_LOS_EdgeOutput
{
	//Array contains both sides of the edge found.
	//The second will have -1's if there is no second side
	Tools_LOS_Edge m_axEdge[2];

	bool m_bDiagonalInQuad;//true if the edge is the diagonal down the middle of a quad.
};


#endif //__TOOLS_LOS_H_
