//! This entity exists both client andserver side
//! when it enters into player's bubble and gets instantiated client-side, it will locally spawn UndergroundTrigger, which is the actual trigger
class UndergroundTriggerCarrier extends UndergroundTriggerCarrierBase
{
	ref JsonUndergroundAreaTriggerData m_Data;
	UndergroundTrigger m_Trigger;
	
	void UndergroundTriggerCarrier()
	{
		RegisterNetSyncVariableInt("m_TriggerIndex", -1, 255);
	}
	
	void ~UndergroundTriggerCarrier()
	{
		if (m_Trigger && !m_Trigger.IsSetForDeletion() && GetGame())
		{
			//RemoveChild(m_Trigger);
			m_Trigger.Delete();
		}
	}
	
	override void OnVariablesSynchronized()
	{
		super.OnVariablesSynchronized();
		if (!m_Trigger)
		{
			SpawnTrigger();
		}
	}
		
	bool CanSpawnTrigger()
	{
		return UndergroundAreaLoader.m_JsonData && m_TriggerIndex != -1;
	}
	
	void RequestDelayedTriggerSpawn()
	{
		//Print("RequestDelayedTriggerSpawn() " + this);
		GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(SpawnTrigger, 100);
	}
	
	void SpawnTrigger()
	{
		
		if (!CanSpawnTrigger())
		{
			RequestDelayedTriggerSpawn();
			return;
		}
		
		if (UndergroundAreaLoader.m_JsonData.Triggers && UndergroundAreaLoader.m_JsonData.Triggers.IsValidIndex(m_TriggerIndex))
		{
			JsonUndergroundAreaTriggerData data = UndergroundAreaLoader.m_JsonData.Triggers[m_TriggerIndex];
			UndergroundTrigger trigger = UndergroundTrigger.Cast(GetGame().CreateObjectEx( "UndergroundTrigger", GetPosition(), ECE_LOCAL ));
			if (trigger)
			{
				#ifdef DIAG_DEVELOPER
				trigger.m_Local = true;
				#endif
				trigger.SetPosition(vector.Zero);
				AddChild(trigger,-1);
				trigger.Init(data);
				
				m_Trigger = trigger;
			}
		}
	}

}

enum EUndergroundTriggerType
{
	UNDEFINED,
	TRANSITIONING,
	OUTER,
	INNER
}

class UndergroundTrigger : ManTrigger
{
	ref JsonUndergroundAreaTriggerData m_Data;
	
	EUndergroundTriggerType m_Type;
	float m_Accommodation;
	float m_InterpolationSpeed;
	
	void Init(JsonUndergroundAreaTriggerData data)
	{
		m_Data = data;
		//Print("Spawning trigger " + this + "at pos: " + GetPosition());
		vector extMax = data.GetSize() * 0.5;
		vector extMin = -extMax;
		SetExtents(extMin, extMax);
		m_Accommodation = data.EyeAccommodation;
		m_InterpolationSpeed = data.InterpolationSpeed;

		if (data.Breadcrumbs && data.Breadcrumbs.Count() > 0) //TODO: simpler check
		{
			if (data.Breadcrumbs.Count() > 32)
			{
				ErrorEx("max 'Breadcrumb' count is 32, found: " + data.Breadcrumbs.Count());
			}
			m_Type = EUndergroundTriggerType.TRANSITIONING;
		}
		else
		{
			if (m_Accommodation == 1)
			{
				m_Type = EUndergroundTriggerType.OUTER;
			}
			else
			{
				m_Type = EUndergroundTriggerType.INNER;
			}
		}
	}

	override protected bool CanAddObjectAsInsider(Object object)
	{
		if (!super.CanAddObjectAsInsider(object))
		{
			return false;
		}
		
		return ManBase.Cast(object).IsControlledPlayer();
	}
	
	
	override void EOnInit(IEntity other, int extra)
	{
		//disable parent behaviour
	}
	
	
	
	
	#ifdef DEVELOPER
	override protected void OnEnterServerEvent(TriggerInsider insider) 
	{
		#ifndef SERVER//to make it work in single during development
		OnEnterClientEvent(insider);
		#endif
	}
	override protected void OnLeaveServerEvent(TriggerInsider insider) 
	{
		#ifndef SERVER//to make it work in single during development
		OnLeaveClientEvent(insider);
		#endif
	}
	#endif
	
	override protected void OnEnterClientEvent(TriggerInsider insider) 
	{
		//Print("OnEnterClientEvent " + this);
		//return;
		PlayerBase player = PlayerBase.Cast(insider.GetObject());
		if (player)
		{
			UndergroundHandlerClient handler = player.GetUndergroundHandler();
			if (handler)
			{
				handler.OnTriggerEnter(this);
			}
		}
	}
	
	override protected void OnLeaveClientEvent(TriggerInsider insider) 
	{
		//Print("OnLeaveClientEvent " + this);
		//return;
		PlayerBase player = PlayerBase.Cast(insider.GetObject());
		if (player)
		{
			UndergroundHandlerClient handler = player.GetUndergroundHandler();
			if (handler)
			{
				handler.OnTriggerLeave(this);
			}
		}
	}

};