enum EGrenadeType
{
	FRAGMENTATION = 0,
	CHEMICAL,
	ILLUMINATING,
	NON_LETHAL
}

//! For backward compatibility
class GrenadeLight : ExplosiveLight {}

class FlashGrenadeLight : PointLightBase
{
	protected static float m_DefaultBrightness	= 50;
	protected static float m_DefaultRadius		= 20;
	
	void FlashGrenadeLight()
	{
		SetVisibleDuringDaylight(true);
		SetRadiusTo(m_DefaultRadius);
		SetBrightnessTo(m_DefaultBrightness);
		SetFlareVisible(false);
		SetAmbientColor(1.0, 1.0, 1.0);
		SetDiffuseColor(1.0, 1.0, 1.0);
		SetLifetime(0.35);
		SetDisableShadowsWithinRadius(-1);
	}
}

class Grenade_Base : ExplosivesBase
{
	protected const float DEFAULT_FUSE_DELAY 	= 10;

	protected ref Timer		m_FuseTimer;
	protected float			m_FuseDelay;
	protected float 		m_RemainingFuseTime;
	
	protected bool			m_Pinned;
	protected bool			m_Pinnable;
	//protected bool		m_Explodable;	//! DEPRECATED; not used anywhere
	
	protected EGrenadeType	m_GrenadeType;

	void Pin()
	{
		if (!m_Pinned && m_Pinnable)
		{
			OnPin();
		}
	}
	
	void Unpin()
	{
		if (m_Pinned)
		{
			OnUnpin();
		}
	}		
	
	//! DEPRECATED use OnActivatedByItem
	override void OnActivatedByTripWire();
	
	override void OnActivatedByItem(notnull ItemBase item)
	{
		if (item == this)
		{
			OnActivateFinished();
			return;
		}

		Unpin();
	}
	
	bool IsPinned()
	{
		return m_Pinned;
	}
	
	bool IsPinnable()
	{
		//! cannot be pinned once the fuse has started
		if (m_FuseTimer.IsRunning())
		{
			return false;	
		}
		
		return m_Pinnable;
	}
	
	void ActivateImmediate()
	{
		OnActivateImmediate();
	}
	
	void ActivateRandomTime()
	{
		float delay = Math.RandomFloat(1, 20);
		delay *= 1000; //! to millis
		GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ActivateImmediate, delay, false);
	}
	
	void SetPinnable(bool state)
	{
		m_Pinnable = state;
	}
	
	void SetFuseDelay(float delay)
	{
		m_FuseDelay = delay;
	}

	void SetGrenadeType(EGrenadeType type)
	{
		m_GrenadeType = type;
	}
	
	EGrenadeType GetGrenadeType()
	{
		return m_GrenadeType;
	}
	
	protected void Activate()
	{
		if (!m_FuseTimer.IsRunning())
		{
			//! run only the remaining part (already unpinned and pinned)
			if (m_RemainingFuseTime > 0)
			{
				//Debug.Log(string.Format("Grenade activated num of seconds to explosion: %1", m_RemainingFuseTime));
				m_FuseTimer.Run(m_RemainingFuseTime, this, "OnActivateFinished");
			}
			else
			{
				//Debug.Log(string.Format("Grenade activated num of seconds to explosion: %1", m_FuseDelay));
				m_FuseTimer.Run(m_FuseDelay, this, "OnActivateFinished");
			}

		}
	}

	protected void Deactivate()
	{
		if (m_FuseTimer.IsRunning())
		{
			m_RemainingFuseTime = m_FuseTimer.GetRemaining();
			m_FuseTimer.Stop();
			OnDeactivate();
		}
	}
	
	protected override void InitiateExplosion()
	{
		switch (GetGrenadeType())
		{
			case EGrenadeType.FRAGMENTATION:
			case EGrenadeType.ILLUMINATING:
				for (int i = 0; i < m_AmmoTypes.Count(); i++)
				{
					Explode(DamageType.EXPLOSION, m_AmmoTypes[i]);
				}
			break;
			case EGrenadeType.CHEMICAL:
			case EGrenadeType.NON_LETHAL:
			break;
		}
		
		OnExplode();	
	}

	//! DEPRECATED - for backward compatibility only
	protected void ExplodeGrenade(EGrenadeType grenade_type)
	{
		InitiateExplosion();
	}

	protected void OnPin()
	{
		m_Pinned = true;
		if (GetGame().IsServer())
		{
			ForceFarBubble(false);
			SetSynchDirty();
		}

		Deactivate();
	}

	protected void OnUnpin()
	{
		m_Pinned = false;
		if (GetGame().IsServer())
		{
			ForceFarBubble(true);
			SetSynchDirty();
		}

		OnActivateStarted();
	}

	protected void OnActivateStarted();
	protected void OnActivateFinished()
	{
		if (GetGame().IsServer())
		{
			SetHealth("", "", 0.0); // causes explosion when grenade is destroyed
			SetTakeable(false);
		}
	}
	
	protected void OnActivateImmediate()
	{
		if (GetGame().IsServer())
		{
			SetHealth("", "", 0.0); // causes explosion when grenade is destroyed
			SetTakeable(false);
		}
	}
	
	protected void OnDeactivate();
	
	override void OnStoreSave(ParamsWriteContext ctx)
	{
		super.OnStoreSave(ctx);
		
		if (GetGame().SaveVersion() >= 107)
		{
			ctx.Write(m_Pinned);
		}
	}
	
	override bool OnStoreLoad(ParamsReadContext ctx, int version)
	{
		if (!super.OnStoreLoad(ctx, version))
			return false;
		
		bool pinned;
		if (version >= 107)
		{
			if (!ctx.Read(pinned))
			{
				return false;
			}
			
			m_Pinned = pinned;
		}

		return true;
	}
	
	override bool CanBeArmed()
	{
		return false;
	}
	
	override bool CanBeDisarmed()
	{
		return false;
	}

	override bool CanExplodeInFire()
	{
		return true;
	}

	override void SetActions()
	{
		super.SetActions();

		AddAction(ActionUnpin);
		AddAction(ActionPin);
	}
	
	override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
	{
		super.EEItemLocationChanged(oldLoc, newLoc);

		//! activate grenade when it leaves player hands (safety handle released)
		if (newLoc.GetType() != InventoryLocationType.HANDS && !IsPinned())
		{
			Activate();
		}
	}
	
	override void OnWasAttached(EntityAI parent, int slot_id)
	{
		super.OnWasAttached(parent, slot_id);
		
		if (parent.IsAnyInherited({TrapBase,ImprovisedExplosive}))
		{
			Deactivate();
		}
	}
	
	void Grenade_Base()
	{
		m_Pinned			= true;
		m_FuseTimer			= new Timer;
		m_RemainingFuseTime = -1;

		SetPinnable(true);
		SetFuseDelay(DEFAULT_FUSE_DELAY);
		SetGrenadeType(EGrenadeType.FRAGMENTATION);
		
		RegisterNetSyncVariableBool("m_Pinned");
	}
	
	override void InitSpecificsExplosionEffectForSurface()
	{
		AddExplosionEffectForSurface("Hit_Snow", ParticleList.EXPLOSION_GRENADE_SNOW);
		AddExplosionEffectForSurface("Hit_Ice", ParticleList.EXPLOSION_GRENADE_ICE);
	}
}