class DelayedVisibilityInAnimSystemRequest extends ScriptableSystemRequest
{
	var data : ForcedVisibilityInAnimSystemData;
	var isVisible : Bool;
	var entityID : EntityID;
}

class ToggleVisibilityInAnimSystemRequest extends ScriptableSystemRequest
{
	var entityID : EntityID;
	var isVisible : Bool;
	var sourceName : CName;
	var transitionTime : Float;
	var forcedVisibleOnlyInFrustum : Bool;
}

class ClearVisibilityInAnimSystemRequest extends ScriptableSystemRequest
{
	var entityID : EntityID;
}

class ForcedVisibilityInAnimSystemData extends IScriptable
{
	var sourceName : CName;
	var delayID : DelayID;
	var forcedVisibleOnlyInFrustum : Bool;
}

class AnimationSystemForcedVisibilityEntityData extends IScriptable
{
	private var m_owner : weak< AnimationSystemForcedVisibilityManager >;
	private var m_entityID : EntityID;
	private var m_forcedVisibilityInAnimSystemRequests : array< ForcedVisibilityInAnimSystemData >;
	private var m_delayedForcedVisibilityInAnimSystemRequests : array< ForcedVisibilityInAnimSystemData >;
	private var m_hasVisibilityForcedInAnimSystem : Bool;
	private var m_hasVisibilityForcedOnlyInFrustumInAnimSystem : Bool;

	public function Initialize( entityID : EntityID, owner : weak< AnimationSystemForcedVisibilityManager > )
	{
		m_owner = owner;
		m_entityID = entityID;
	}

	public function ClearAllRequests()
	{
		m_forcedVisibilityInAnimSystemRequests.Clear();
		m_delayedForcedVisibilityInAnimSystemRequests.Clear();
	}

	public const function GetEntityID() : EntityID
	{
		return m_entityID;
	}

	public const function HasVisibilityForcedInAnimSystem() : Bool
	{
		return m_hasVisibilityForcedInAnimSystem;
	}

	public const function HasActiveRequestsForForcedVisibilityInAnimSystem() : Bool
	{
		return m_forcedVisibilityInAnimSystemRequests.Size() > 0;
	}

	public function SetHasVisibilityForcedInAnimSystem( isVisible : Bool )
	{
		m_hasVisibilityForcedInAnimSystem = isVisible;
	}

	public const function HasVisibilityForcedOnlyInFrustumInAnimSystem() : Bool
	{
		return m_hasVisibilityForcedOnlyInFrustumInAnimSystem;
	}

	public const function HasActiveRequestsForForcedVisibilityOnlyInFrustumInAnimSystem() : Bool
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].forcedVisibleOnlyInFrustum )
			{
				return true;
			}
		}
		return false;
	}

	public function SetHasVisibilityForcedOnlyInFrustumInAnimSystem( isVisible : Bool )
	{
		m_hasVisibilityForcedOnlyInFrustumInAnimSystem = isVisible;
	}

	public function AddForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData )
	{
		if( !( HasForcedVisiblityInAnimSystemRequest( data.sourceName ) ) )
		{
			m_forcedVisibilityInAnimSystemRequests.PushBack( data );
		}
	}

	public function RemoveForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData )
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].sourceName == data.sourceName )
			{
				m_forcedVisibilityInAnimSystemRequests[ i ] = NULL;
				m_forcedVisibilityInAnimSystemRequests.Erase( i );
				return;
			}
		}
	}

	public function RemoveForcedVisiblityInAnimSystemRequest( sourceName : CName )
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].sourceName == sourceName )
			{
				m_forcedVisibilityInAnimSystemRequests[ i ] = NULL;
				m_forcedVisibilityInAnimSystemRequests.Erase( i );
				return;
			}
		}
	}

	public function HasForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].sourceName == data.sourceName )
			{
				return true;
			}
		}
		return false;
	}

	public function HasForcedVisiblityInAnimSystemRequest( sourceName : CName ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].sourceName == sourceName )
			{
				return true;
			}
		}
		return false;
	}

	public function GetForcedVisiblityInAnimSystemRequest( sourceName : CName ) : ForcedVisibilityInAnimSystemData
	{
		var i : Int32;
		for( i = 0; i < m_forcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_forcedVisibilityInAnimSystemRequests[ i ].sourceName == sourceName )
			{
				return m_forcedVisibilityInAnimSystemRequests[ i ];
			}
		}
		return NULL;
	}

	public function HasDelayedForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_delayedForcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_delayedForcedVisibilityInAnimSystemRequests[ i ].sourceName == data.sourceName )
			{
				return true;
			}
		}
		return false;
	}

	public function HasDelayedForcedVisiblityInAnimSystemRequest( sourceName : CName ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_delayedForcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_delayedForcedVisibilityInAnimSystemRequests[ i ].sourceName == sourceName )
			{
				return true;
			}
		}
		return false;
	}

	public function GetDelayedForcedVisiblityInAnimSystemRequest( sourceName : CName ) : ForcedVisibilityInAnimSystemData
	{
		var i : Int32;
		for( i = 0; i < m_delayedForcedVisibilityInAnimSystemRequests.Size(); i += 1 )
		{
			if( m_delayedForcedVisibilityInAnimSystemRequests[ i ].sourceName == sourceName )
			{
				return m_delayedForcedVisibilityInAnimSystemRequests[ i ];
			}
		}
		return NULL;
	}

	public function RemoveDelayedForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData )
	{
		if( data == NULL )
		{
			return;
		}
		m_delayedForcedVisibilityInAnimSystemRequests.Remove( data );
		data = NULL;
	}

	public function AddDelayedForcedVisiblityInAnimSystemRequest( data : ForcedVisibilityInAnimSystemData )
	{
		if( !( HasDelayedForcedVisiblityInAnimSystemRequest( data ) ) )
		{
			m_delayedForcedVisibilityInAnimSystemRequests.PushBack( data );
		}
	}

}

class AnimationSystemForcedVisibilityManager extends ScriptableSystem
{
	private var m_entities : array< AnimationSystemForcedVisibilityEntityData >;

	private function ClearEntity( id : EntityID )
	{
		var entityData : AnimationSystemForcedVisibilityEntityData;
		entityData = GetEntityData( id );
		if( entityData != NULL )
		{
			entityData.ClearAllRequests();
			ResovleVisibilityInAnimSystem( entityData );
		}
	}

	protected function ToggleForcedVisibilityInAnimSystem( entityID : EntityID, sourceName : CName, isVisible : Bool, optional transitionTime : Float, optional forcedVisibleOnlyInFrustum : Bool )
	{
		var entityData : AnimationSystemForcedVisibilityEntityData;
		var visibilityData : ForcedVisibilityInAnimSystemData;
		entityData = GetEntityData( entityID );
		if( !( isVisible ) && ( entityData == NULL ) )
		{
			return;
		}
		if( entityData == NULL )
		{
			entityData = new AnimationSystemForcedVisibilityEntityData;
			entityData.Initialize( entityID, this );
			m_entities.PushBack( entityData );
		}
		visibilityData = entityData.GetDelayedForcedVisiblityInAnimSystemRequest( sourceName );
		if( visibilityData )
		{
			CancelDelayedRequestForVisilityData( visibilityData );
			entityData.RemoveDelayedForcedVisiblityInAnimSystemRequest( visibilityData );
		}
		if( transitionTime > 0.0 )
		{
			visibilityData = new ForcedVisibilityInAnimSystemData;
			visibilityData.sourceName = sourceName;
			visibilityData.forcedVisibleOnlyInFrustum = forcedVisibleOnlyInFrustum;
			SendDelayedRequestForVisilityData( entityID, isVisible, transitionTime, visibilityData );
			entityData.AddDelayedForcedVisiblityInAnimSystemRequest( visibilityData );
		}
		else
		{
			if( isVisible )
			{
				visibilityData = new ForcedVisibilityInAnimSystemData;
				visibilityData.sourceName = sourceName;
				visibilityData.forcedVisibleOnlyInFrustum = forcedVisibleOnlyInFrustum;
				entityData.AddForcedVisiblityInAnimSystemRequest( visibilityData );
			}
			else
			{
				entityData.RemoveForcedVisiblityInAnimSystemRequest( sourceName );
			}
		}
		ResovleVisibilityInAnimSystem( entityData );
	}

	private function SendDelayedRequestForVisilityData( entityID : EntityID, isVisible : Bool, transitionTime : Float, data : ForcedVisibilityInAnimSystemData )
	{
		var request : DelayedVisibilityInAnimSystemRequest;
		request = new DelayedVisibilityInAnimSystemRequest;
		request.isVisible = isVisible;
		request.data = data;
		request.entityID = entityID;
		data.delayID = GameInstance.GetDelaySystem( GetGameInstance() ).DelayScriptableSystemRequest( 'AnimationSystemForcedVisibilityManager', request, transitionTime, false );
	}

	private function CancelDelayedRequestForVisilityData( data : ForcedVisibilityInAnimSystemData )
	{
		var invalidDelayID : DelayID;
		if( data == NULL )
		{
			return;
		}
		if( data.delayID != invalidDelayID )
		{
			GameInstance.GetDelaySystem( GetGameInstance() ).CancelDelay( data.delayID );
		}
	}

	protected function ResovleVisibilityInAnimSystem( entityData : AnimationSystemForcedVisibilityEntityData )
	{
		if( entityData == NULL )
		{
			return;
		}
		if( entityData.HasActiveRequestsForForcedVisibilityOnlyInFrustumInAnimSystem() )
		{
			if( !( entityData.HasVisibilityForcedOnlyInFrustumInAnimSystem() ) )
			{
				GameInstance.GetAnimationSystem( GetGameInstance() ).SetForcedVisibleOnlyInFrustum( entityData.GetEntityID(), true );
				entityData.SetHasVisibilityForcedOnlyInFrustumInAnimSystem( true );
			}
		}
		else
		{
			if( entityData.HasVisibilityForcedOnlyInFrustumInAnimSystem() )
			{
				GameInstance.GetAnimationSystem( GetGameInstance() ).SetForcedVisibleOnlyInFrustum( entityData.GetEntityID(), false );
				entityData.SetHasVisibilityForcedOnlyInFrustumInAnimSystem( false );
			}
		}
		if( entityData.HasActiveRequestsForForcedVisibilityInAnimSystem() )
		{
			if( !( entityData.HasVisibilityForcedInAnimSystem() ) )
			{
				GameInstance.GetAnimationSystem( GetGameInstance() ).SetForcedVisible( entityData.GetEntityID(), true );
				entityData.SetHasVisibilityForcedInAnimSystem( true );
			}
		}
		else
		{
			if( entityData.HasVisibilityForcedInAnimSystem() )
			{
				GameInstance.GetAnimationSystem( GetGameInstance() ).SetForcedVisible( entityData.GetEntityID(), false );
				entityData.SetHasVisibilityForcedInAnimSystem( false );
			}
			m_entities.Remove( entityData );
		}
	}

	private function GetEntityData( id : EntityID ) : AnimationSystemForcedVisibilityEntityData
	{
		var i : Int32;
		for( i = 0; i < m_entities.Size(); i += 1 )
		{
			if( m_entities[ i ].GetEntityID() == id )
			{
				return m_entities[ i ];
			}
		}
		return NULL;
	}

	private function IsEntityRegistered( id : EntityID ) : Bool
	{
		return GetEntityData( id ) != NULL;
	}

	private export function OnToggleVisibilityInAnimSystemRequest( request : ToggleVisibilityInAnimSystemRequest )
	{
		ToggleForcedVisibilityInAnimSystem( request.entityID, request.sourceName, request.isVisible, request.transitionTime, request.forcedVisibleOnlyInFrustum );
	}

	private export function OnClearVisibilityInAnimSystemRequest( request : ClearVisibilityInAnimSystemRequest )
	{
		ClearEntity( request.entityID );
	}

	protected export function OnHandleDelayedVisibilityInAnimSystemRequest( request : DelayedVisibilityInAnimSystemRequest )
	{
		var invalidID : DelayID;
		if( request.data == NULL )
		{
			return;
		}
		request.data.delayID = invalidID;
		ToggleForcedVisibilityInAnimSystem( request.entityID, request.data.sourceName, request.isVisible );
	}

	public const function HasVisibilityForced( id : EntityID ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_entities.Size(); i += 1 )
		{
			if( m_entities[ i ].GetEntityID() == id )
			{
				return true;
			}
		}
		return false;
	}

}

