namespace BP
{
	namespace Ailments
	{
		funcdef void AilmentChangeCallBack();
		
		const int TYPE_REGEN = 0;
		const int TYPE_QUAD = 1;
		const int TYPE_HASTE = 2;
		const int TYPE_STUN = 3;
		//------------------------------------------------------------------------------------------------------------------------
		Ailment@ GetAilmentByType(const int type)
		{
			switch (type)
			{
				case TYPE_REGEN:
				{
					return Regen();
				}
				case TYPE_QUAD:
				{
					return Quad();
				}
				case TYPE_HASTE:
				{
					return Haste();
				}
				case TYPE_STUN:
				{
					return Stun();
				}
			}
			
			return Ailment();
		}
		//========================================================================================================================
		class AilmentMan
		{
			array<Ailment@> ailments;
			AilmentChangeCallBack@ onChange;
			//------------------------------------------------------------------------------------------------------------------------
			AilmentMan() {}
			//------------------------------------------------------------------------------------------------------------------------
			void OnSerialize(kDict dict)
			{
				int ailmentsLength = int(ailments.length);
				SERIALIZE_INT(ailmentsLength);
				for (int i = 0; i < ailmentsLength; i++)
				{
					ailments[i].Serialize(dict, "ailments" + i);
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnDeserialize(kDict& in dict)
			{
				ailments.resize(0);
				int ailmentsLength;
				DESERIALIZE_INT(ailmentsLength);
				ailments.resize(ailmentsLength);
				for (int i = 0; i < ailmentsLength; i++)
				{
					kStr key = "ailments" + i;
					int type;
					DESERIALIZEKEY_INT(key, type);
					@ailments[i] = @GetAilmentByType(type);
					ailments[i].Deserialize(dict, "ailments" + i);
				}
				
				OnChange();
			}
			//------------------------------------------------------------------------------------------------------------------------
			float DamageBonus()
			{
				float damageBonus = 0.0f;
				int ailmentsLength = int(ailments.length);
				for (int i = 0; i < ailmentsLength; i++)
				{
					damageBonus += ailments[i].DamageBonus();
				}
				return damageBonus;
			}
			//------------------------------------------------------------------------------------------------------------------------
			float SpeedBonus()
			{
				float speedBonus = 0.0f;
				int ailmentsLength = int(ailments.length);
				for (int i = 0; i < ailmentsLength; i++)
				{
					speedBonus += ailments[i].SpeedBonus();
				}
				return speedBonus;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnChange()
			{
				if (@onChange != null)
				{
					onChange();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			// Add an Ailment type if that ailment hasn't already been added
			//------------------------------------------------------------------------------------------------------------------------
			Ailment@ Add(int type)
			{
				//Check if Ailment already exists if so then start it up again
				int ailmentsLength = int(ailments.length);
				for (int i = ailmentsLength - 1; i >= 0; i--)
				{
					if (ailments[i].type == type)
					{
						ailments[i].OnDisable();
						ailments[i].OnEnable();
						OnChange();
						return @ailments[i];
					}
				}
				
				Ailment @ailment = @GetAilmentByType(type);
				Add(@ailment);
				return @ailment;
			}
			//------------------------------------------------------------------------------------------------------------------------
			private void Add(Ailment@ ailment)
			{
				ailments.insertLast(@ailment);
				ailment.OnEnable();
				OnChange();
			}
			//------------------------------------------------------------------------------------------------------------------------
			// Remove all Ailments with type
			//------------------------------------------------------------------------------------------------------------------------
			void Remove(int type)
			{
				bool changed = false;
				int ailmentsLength = int(ailments.length);
				for (int i = ailmentsLength - 1; i >= 0; i--)
				{
					if (ailments[i].type == type)
					{
						changed = true;
						ailments[i].OnDisable();
						ailments.removeAt(i);
					}
				}
				if (changed)
				{
					OnChange();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void RemoveAll()
			{
				int ailmentsLength = int(ailments.length);
				if (ailmentsLength > 0)
				{
					for (int i = ailmentsLength - 1; i >= 0; i--)
					{
						ailments[i].OnDisable();
					}
					ailments.resize(0);
					OnChange();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnTick()
			{
				bool changed = false;
				int ailmentsLength = int(ailments.length);
				for (int i = ailmentsLength - 1; i >= 0; i--)
				{
					ailments[i].OnTick();
					if (!ailments[i].IsActive()) 
					{
						changed = true;
						ailments[i].OnDisable();
						ailments.removeAt(i);
					}
				}
				
				if (changed)
				{
					OnChange();
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
		};
	}
}
