namespace DotRecast.Detour
{
	internal static class DtDetour
	{
		/// The maximum number of vertices per navigation polygon.
		/// @ingroup detour
		public const int DT_VERTS_PER_POLYGON = 6;

		/** A magic number used to detect compatibility of navigation tile data. */
		public const int DT_NAVMESH_MAGIC = 'D' << 24 | 'N' << 16 | 'A' << 8 | 'V';

		/** A version number used to detect compatibility of navigation tile data. */
		public const int DT_NAVMESH_VERSION = 7;

		public const int DT_NAVMESH_VERSION_RECAST4J_FIRST = 0x8807;
		public const int DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK = 0x8808;
		public const int DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE = 0x8809;
		public const int DT_NAVMESH_VERSION_RECAST4J_LAST = 0x8809;

		/** A magic number used to detect the compatibility of navigation tile states. */
		public const int DT_NAVMESH_STATE_MAGIC = 'D' << 24 | 'N' << 16 | 'M' << 8 | 'S';

		/** A version number used to detect compatibility of navigation tile states. */
		public const int DT_NAVMESH_STATE_VERSION = 1;

		public const int DT_SALT_BITS = 16;
		public const int DT_TILE_BITS = 28;
		public const int DT_POLY_BITS = 20;

		/// A flag that indicates that an entity links to an external entity.
		/// (E.g. A polygon edge is a portal that links to another polygon.)
		public const int DT_EXT_LINK = 0x8000;

		/// A value that indicates the entity does not link to anything.
		public const int DT_NULL_LINK = unchecked((int)0xffffffff);

		public const int DT_NODE_PARENT_BITS = 24;
		public const int DT_NODE_STATE_BITS = 2;
		public const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state

		/// The maximum number of user defined area ids.
		public const int DT_MAX_AREAS = 64;

		/// Limit raycasting during any angle pahfinding
		/// The limit is given as a multiple of the character radius
		public const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;

		/// @{
		/// @name Encoding and Decoding
		/// These functions are generally meant for internal use only.
		/// Derives a standard polygon reference.
		///  @note This function is generally meant for internal use only.
		///  @param[in]	salt	The tile's salt value.
		///  @param[in]	it		The index of the tile.
		///  @param[in]	ip		The index of the polygon within the tile.
		public static long EncodePolyId( int salt, int it, int ip )
		{
			return (((long)salt) << (DT_POLY_BITS + DT_TILE_BITS)) | ((long)it << DT_POLY_BITS) | (long)ip;
		}

		/// Decodes a standard polygon reference.
		/// @note This function is generally meant for internal use only.
		/// @param[in] ref The polygon reference to decode.
		/// @param[out] salt The tile's salt value.
		/// @param[out] it The index of the tile.
		/// @param[out] ip The index of the polygon within the tile.
		/// @see #encodePolyId
		public static void DecodePolyId( long refs, out int salt, out int it, out int ip )
		{
			long saltMask = (1L << DT_SALT_BITS) - 1;
			long tileMask = (1L << DT_TILE_BITS) - 1;
			long polyMask = (1L << DT_POLY_BITS) - 1;
			salt = (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
			it = (int)((refs >> DT_POLY_BITS) & tileMask);
			ip = (int)(refs & polyMask);
		}

		/// Extracts a tile's salt value from the specified polygon reference.
		/// @note This function is generally meant for internal use only.
		/// @param[in] ref The polygon reference.
		/// @see #encodePolyId
		public static int DecodePolyIdSalt( long refs )
		{
			long saltMask = (1L << DT_SALT_BITS) - 1;
			return (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
		}

		/// Extracts the tile's index from the specified polygon reference.
		/// @note This function is generally meant for internal use only.
		/// @param[in] ref The polygon reference.
		/// @see #encodePolyId
		public static int DecodePolyIdTile( long refs )
		{
			long tileMask = (1L << DT_TILE_BITS) - 1;
			return (int)((refs >> DT_POLY_BITS) & tileMask);
		}

		/// Extracts the polygon's index (within its tile) from the specified
		/// polygon reference.
		/// @note This function is generally meant for internal use only.
		/// @param[in] ref The polygon reference.
		/// @see #encodePolyId
		public static int DecodePolyIdPoly( long refs )
		{
			long polyMask = (1L << DT_POLY_BITS) - 1;
			return (int)(refs & polyMask);
		}

		public static int ComputeTileHash( int x, int y, int mask )
		{
			uint h1 = 0x8da6b343; // Large multiplicative constants;
			uint h2 = 0xd8163841; // here arbitrarily chosen primes
			uint n = h1 * (uint)x + h2 * (uint)y;
			return (int)(n & mask);
		}

		public static float GetSlabCoord( Vector3 vert, int side )
		{
			if ( side == 0 || side == 4 )
			{
				return vert.x;
			}
			else if ( side == 2 || side == 6 )
			{
				return vert.z;
			}

			return 0;
		}

		public static void CalcSlabEndPoints( Vector3 va, Vector3 vb, ref Vector2 bmin, ref Vector2 bmax, int side )
		{
			if ( side == 0 || side == 4 )
			{
				if ( va.z < vb.z )
				{
					bmin.x = va.z;
					bmin.y = va.y;
					bmax.x = vb.z;
					bmax.y = vb.y;
				}
				else
				{
					bmin.x = vb.z;
					bmin.y = vb.y;
					bmax.x = va.z;
					bmax.y = va.y;
				}
			}
			else if ( side == 2 || side == 6 )
			{
				if ( va.x < vb.x )
				{
					bmin.x = va.x;
					bmin.y = va.y;
					bmax.x = vb.x;
					bmax.y = vb.y;
				}
				else
				{
					bmin.x = vb.x;
					bmin.y = vb.y;
					bmax.x = va.x;
					bmax.y = va.y;
				}
			}
		}

		/// Get flags for edge in detail triangle.
		/// @param[in]	triFlags		The flags for the triangle (last component of detail vertices above).
		/// @param[in]	edgeIndex		The index of the first vertex of the edge. For instance, if 0,
		///								returns flags for edge AB.
		public static int GetDetailTriEdgeFlags( int triFlags, int edgeIndex )
		{
			return (triFlags >> (edgeIndex * 2)) & 0x3;
		}
	}
}
