#pragma once

#include "MW4.hpp"

namespace Adept
{
	class Effect;
}

namespace MechWarrior4
{

	class Mech;


	void HeatSecurityCheckStart();
	void HeatSecurityCheckStop();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// HeatObject
	//
	class HeatObject: public Stuff::Plug
	{
	public:
		HeatObject(Stuff::Scalar time_applied, Stuff::Scalar heat_applied, bool is_permanent = false) :
			Stuff::Plug(Stuff::Plug::DefaultData)
		{
			timesApplied=(int)(time_applied / 0.5f);
			heatApplied=(Stuff::Scalar)(heat_applied / timesApplied);
			currentCount=0;
			isPermanent = is_permanent;
		}
		HeatObject(Stuff::Scalar heat_applied, bool is_permanent = true) :
			Stuff::Plug(Stuff::Plug::DefaultData)
		{
			timesApplied=0;
			heatApplied=heat_applied;
			currentCount=0;
			isPermanent = is_permanent;
		}
		~HeatObject() {}

		int timesApplied;
		Stuff::Scalar heatApplied;
		int currentCount;
		bool isPermanent;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// HeatManager
	//
	typedef Adept::Receiver__ClassData			HeatManager__ClassData;
	typedef Adept::Receiver__Message			HeatManager__Message;

	class HeatManager:
		public Adept::Receiver
	{
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance Support
	//
	public:
		typedef HeatManager__ClassData			ClassData;
		typedef HeatManager__Message			Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, Testing
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		HeatManager(
			Stuff::Scalar max_heat,
			Stuff::Scalar current_heat,
			Stuff::Scalar max_coolant,
			Stuff::Scalar current_coolant,
			Mech *parent,
			Adept::ResourceID stream_id
			);

		~HeatManager();

		void
			Reuse();
		void
      		TestInstance();
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation support
	//
	public:
		
		bool shutdown;
		//
		//------------
		//Heat Support
		//------------
		//
		bool
			Execute();
		void
			AddHeat(Stuff::Scalar added_heat);
		HeatObject*
			AddHeatObject(Stuff::Scalar time_applied, Stuff::Scalar heat_applied, bool is_permanent=false);
		HeatObject*
			AddHeatObject(Stuff::Scalar heat_applied, bool is_permanent=true);
		Stuff::Scalar
			GetHeat()
				{Check_Object(this); return heatValue;}
		Stuff::Scalar
			GetMaxHeat()
				{Check_Object(this); return maxHeat;}
		Stuff::Scalar
			GetHeatPercentage()
			{
				Check_Object(this);

				if (maxHeat == 0.0f)
						return 0.0f;

				Stuff::Scalar heat_percent = (Stuff::Scalar)(heatValue / maxHeat);
				Clamp(heat_percent,0.0f,1.0f);
				return heat_percent;
			}
		
		Stuff::Scalar
			EstimateMaxCurrentHeat();
		void
			ApplyMovementHeat(Stuff::Scalar current_rate, Stuff::Scalar max_rate);

		Stuff::ChainOf<HeatObject *> heatObjects;

		//
		//---------------
		//Coolant Support
		//---------------
		//
		void
			AddCoolant(Stuff::Scalar added_coolant)
				{Check_Object(this); coolantValue += added_coolant;
				Clamp(coolantValue, 0.0f, maxCoolant);
				isCoolantDirty = 1;}

		Stuff::Scalar
			GetCoolant()
				{Check_Object(this); return coolantValue;}
		Stuff::Scalar
			GetCoolantPercentage()
				{
					Check_Object(this);

					if (maxCoolant == 0.0f)
						return 0.0f;

					Scalar percent = coolantValue / maxCoolant;
					Clamp(percent, 0.0f, 1.0f);
					return percent;
				}

		Stuff::Scalar
			GetMaxCoolant()
				{Check_Object(this); return maxCoolant;}
		void
			SetMaxCoolant(Stuff::Scalar max_coolant)
				{Check_Object(this); maxCoolant = max_coolant;}

		void SetCooling(int new_int);

		int
			IsCooling()
				{Check_Object(this); return (isCooling&&(coolantValue>0));}

		//
		//Heat Effects
		//
		Stuff::Scalar
			GetSpeedMultiplier();
		Stuff::Scalar
			GetTorsoTwistMultiplier();

		//Note these are used for the HUD only.  The return an int value of the percentage
		void
			SetCoolantPercentage();
		void
			SetHeatPercentage();

		void
			SetCoolantPercentage(Stuff::Scalar percentage);
		void
			SetHeatPercentage(Stuff::Scalar percentage);

		bool
			OverrideShutDown();

		int heatPercentage;
		int coolantPercentage;
		int isHeatDirty;
		int isCoolantDirty;

		Stuff::Time lastTime;
		Stuff::Time lastCoolTime;

		Stuff::SlotOf<Adept::Effect *>
			coolantEffect;
		Stuff::SlotOf<Adept::Effect *>
			overHeatEffect;

		static bool g_OverrideHeatOption;

	protected:
		Stuff::Scalar
			heatValue;
		Stuff::Scalar
			maxHeat;
		Stuff::Scalar
			coolantValue;
		Stuff::Scalar
			maxCoolant;

		int isCooling;
		bool m_shuttingDown;
		bool m_startingUp;

		Stuff::Scalar
			m_movementHeat;
		Stuff::Scalar
			m_doubleMovementHeat;
		Stuff::Scalar
			m_heatEffectsSpeed;
		Stuff::Scalar
			m_shutDownTime;
		Stuff::Time
			m_shutDownTimer;
		Stuff::Time
			m_startUpTimer;
		Stuff::Time
			m_overHeatCheckTime;
		Stuff::Time
			m_overHeatTimer;
// MSL 5.03 Lava
		Stuff::Time
			m_maxHeatTimer;
		bool
			over90;
// MSL 5.03 Lava
		bool
			atMaxHeat;

		Mech *m_parentMech;
		HeatObject *m_movementHeatObject;
	};
}