#pragma once

#include "Adept.hpp"
#include <ElementRenderer\GridElement.hpp>

namespace gosFX {class Light;}

namespace MidLevelRenderer {class MLRTexture;}

//#########################################################################
//#########################  GridElement  ###############################
//#########################################################################

namespace Adept {

	class Tile;
	class Entity;
	class Entity__CollisionQuery;

	class CollisionGrid:
		public ElementRenderer::GridElement
	{
		friend class Map;
		friend class Zone;
		friend class Tile;
		friend class FiniteLight;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Initialization
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors/Destructors
	//
	public:
		CollisionGrid(
			BYTE row_size,
			BYTE column_size,
			Stuff::Scalar row_offset,
			Stuff::Scalar column_offset,
			Stuff::Scalar total_row_size,
			Stuff::Scalar total_column_size,
			Stuff::Scalar water_depth
		);
		~CollisionGrid();

		void
			TestInstance();

		static CollisionGrid*
			Instance;
		static bool
			s_ignoreOBBCollisions;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Hierarchy
	//
	public:
		void
			AttachIndexedChild(
				BYTE row,
				BYTE column,
				Tile *tile
			);
		Tile*
			GetTile(
				BYTE row,
				BYTE column
			);

		int
			EntitiesInTile(
				BYTE row,
				BYTE column
			);

		Tile*
			GetTile(WORD index);


		bool
			MakeFootStep(const LinearMatrix4D& where, Scalar radius, MidLevelRenderer::MLRTexture *foot_texture);

	protected:
		Stuff::ChainOf<Entity*>
			m_lineColliders,
			m_solidColliders;
		Stuff::ChainOf<Tile*>
			m_collidingTiles;
		Stuff::SlotOf<Tile*>
			**m_tileArray;
		Stuff::Plane
			m_waterLevel;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Collision
	//
	public:
		Entity*
			ProjectLine(Entity__CollisionQuery *query);

		void
			FindCollisions(Stuff::Time till);

		typedef void
			(*WithinCallback)(Entity *entity, Entity *original_caller, const Stuff::Sphere &sphere);
		void
			FindEntitiesWithin(
				const Stuff::Sphere &sphere,
				WithinCallback callback,
				Entity *original_caller
			);
	};

}
