#pragma once

#include "MW4.hpp"
#include "Subsystem.hpp"
#include "SensorCellMap.hpp"

namespace MechWarrior4
{
	class Vehicle;
	class Sensor;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	class SensorData :
		public Plug
	{
	public:
		SensorData(
			MWObject *entity,
			Stuff::Scalar target_distance_squared,
			int target_alignment,
			int chasis_type
		);
		SensorData();

		~SensorData();

		SlotOf<MWObject *>
			object;
		Stuff::Scalar
			distanceSquared;
		int
			alignment,
			chasisType;
	};

	//##########################################################################
	//###############    Sensor::ExecutionStateEngine    #######################
	//##########################################################################

	class Sensor__ExecutionStateEngine:
		public Subsystem__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Sensor__ExecutionStateEngine*
			(*Factory)(
				Sensor *weapon,
				FactoryRequest *request
			);

		static Sensor__ExecutionStateEngine*
			Make(
				Sensor *weapon,
				FactoryRequest *request
			);

	protected:
		Sensor__ExecutionStateEngine(
			ClassData *class_data,
			Sensor *weapon,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			ActiveState = Subsystem__ExecutionStateEngine::StateCount,
			PassiveState,
			BeagleState,
			StateCount
		};

	protected:
		static const StateEntry
			StateEntries[];
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      	TestInstance() const;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	typedef Subsystem__ClassData						Sensor__ClassData;
	typedef Subsystem__Message							Sensor__Message;
	typedef Subsystem__CreateMessage					Sensor__CreateMessage;
	typedef Subsystem__GameModel						Sensor__GameModel;

	//##########################################################################
	//###########################   Sensor    ##################################
	//##########################################################################

	class Sensor:
		public Subsystem
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance support
	//
	public:
		typedef Sensor__ClassData						ClassData;
		typedef Sensor__GameModel						GameModel;
		typedef Sensor__Message							Message;
		typedef Sensor__ExecutionStateEngine			ExecutionStateEngine;
		typedef Sensor__CreateMessage					CreateMessage;


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static Sensor*
			Make(
				CreateMessage *message,
				ReplicatorID *base_id
			);
	
	protected:
		Sensor(
			ClassData *class_data,
			CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);

		~Sensor();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data & Game Model Support
	//
	public:
		
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	public:
		void
			PreCollisionExecute(Stuff::Time till);
		void
			UpdateBuildingData();

		void
			CheckForNarc (void);

		//void
		//	CheckForPlayerContacts(int array);

		void CheckBuilding(Entity *entity, Entity *original_enitiy);

		void CheckEntity(MWObject &mwobject);

		void Refresh();

		typedef Stuff::StaticArrayOf<SensorData*, 32> sensorDataArray;

		const sensorDataArray& RefreshAndGetSensorData();
		const sensorDataArray& GetSensorData() const { return (sensorData); }
		const sensorDataArray& GetBuildingData() const { return (buildingData); }
		bool SensorDataOK(SensorData& data, int alignment);

		Scalar
			GetLastTimeUpdatedBuildingData() const;

		int
			numberOfContacts;
		int
			numberOfBuildingContacts;

		enum{
			ActiveMode = 0,
			PassiveMode,
			ShutdownMode
		};

		void SetSensorMode(int mode, bool has_beagle);
		int GetSensorMode (void)
		{ return sensorMode; }

		void
			AddBuildingContact(MWObject *building, Stuff::Scalar target_distance_squared);
		void
			DestroySubsystem();
		bool
			TakeCriticalHit()
				{Check_Object(this); return false;}
		Stuff::Scalar
			GetMaxRange();
		Adept::Entity
			*GetNearestEnemy();
		Adept::Entity
			*GetNextEnemy(Adept::Entity *current_friendly, bool previous = false);
		Adept::Entity
			*GetNearestFriendly();
		Adept::Entity
			*GetNextFriendly(Adept::Entity *current_friendly, bool previous = false);
		bool
			ContainsEntity(Adept::Entity* entity);

		int
			sensorMode;
		Scalar
			m_maxRange;
		Scalar
			executionTimer;
		Scalar m_UpdateTime;

		Scalar
			m_LastUpdateTime;

	protected:
		Stuff::SlotOf<Entity *>
			m_nearestEnemy;
		Stuff::Scalar
			m_nearestEnemyRange;
		Stuff::SlotOf<Entity *>
			m_nearestFriendly;
		Stuff::Scalar
			m_nearestFriendlyRange;

		Stuff::Scalar
			m_LastTimeUpdatedBuildingData;

		int
			m_ContainsEntityLastIndex;

		Stuff::Scalar
			m_ShutdownRange;
		Stuff::Scalar
			m_PassiveRange;
		Stuff::Scalar
			m_ECMRange;
		Stuff::Scalar
			m_NormalRange;
		Stuff::Point3D
			m_ParentVehiclePos;

		sensorDataArray
			sensorData;
		sensorDataArray
			buildingData;

		SensorCellMap::checksum_type
			m_BuildingChecksumList;

		SensorCellMap::checksum_type
			m_ChecksumList;

		void
			DetermineRanges();

		void
			CheckForContacts_VehiclesAndTurrets();

		void
			CheckForContacts_Buildings();

		bool
			CanSeeEntity(MWObject& mwobject);

		Stuff::Scalar
			SquaredRangeToEntity(MWObject& mwobject);

		Stuff::Scalar
			CurrentMaxDetectionRangeTo(MWObject& mwobject);

		static Stuff::Time
			s_LastSensorCheck;

		bool
			m_NeedsSensorRefresh;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      		TestInstance() const;
	};

	inline
		Sensor__ExecutionStateEngine::Sensor__ExecutionStateEngine(
			ClassData *class_data,
			Sensor *mover,
			FactoryRequest *request
		):
			Subsystem__ExecutionStateEngine(class_data, mover, request)
	{
	}
}


