enum EInkAnimationPlaybackOption
{
	PLAY = 0,
	STOP = 1,
	PAUSE = 2,
	RESUME = 3,
	CONTINUE = 4,
	GO_TO_START = 5,
	GO_TO_END = 6,
}

import struct inkAnimOptions
{
	import editable var playReversed : Bool;
	import editable var executionDelay : Float;
	import editable var loopType : inkanimLoopType;
	import editable var loopCounter : Uint32;
	import editable var loopInfinite : Bool;
	import editable var fromMarker : CName;
	import editable var toMarker : CName;
	import editable var oneSegment : Bool;
	import editable var dependsOnTimeDilation : Bool;
	import editable var applyCustomTimeDilation : Bool;
	import editable var customTimeDilation : Float;
}

function GetAnimOptionsInfiniteLoop( loopType : inkanimLoopType ) : inkAnimOptions
{
	var animOptions : inkAnimOptions;
	animOptions.loopType = loopType;
	animOptions.loopInfinite = true;
	return animOptions;
}

struct SWidgetAnimationData
{
	instanceeditable var m_animationName : CName;
	instanceeditable var m_playbackOptions : inkAnimOptions;
	instanceeditable var m_lockWhenActive : Bool;
	var m_animProxy : inkAnimProxy;
	[ category = "Callbacks" ]
	instanceeditable var m_onFinish : CName;
	[ category = "Callbacks" ]
	instanceeditable var m_onStart : CName;
	[ category = "Callbacks" ]
	instanceeditable var m_onPasue : CName;
	[ category = "Callbacks" ]
	instanceeditable var m_onResume : CName;
	[ category = "Callbacks" ]
	instanceeditable var m_onStartLoop : CName;
	[ category = "Callbacks" ]
	instanceeditable var m_onEndLoop : CName;
}

class PlaybackOptionsUpdateData extends IScriptable
{
	instanceeditable var m_playbackOptions : inkAnimOptions;
}

class WidgetAnimationManager extends IScriptable
{
	private mutable instanceeditable var m_animations : array< SWidgetAnimationData >;

	public function Initialize( const animations : ref< array< SWidgetAnimationData > > )
	{
		m_animations = animations;
	}

	public const function GetAnimations() : array< SWidgetAnimationData >
	{
		return m_animations;
	}

	public function UpdateAnimationsList( animName : CName, updateData : PlaybackOptionsUpdateData )
	{
		var animationData : SWidgetAnimationData;
		if( !( updateData ) )
		{
			return;
		}
		if( !( HasAnimation( animName ) ) )
		{
			animationData.m_animationName = animName;
			animationData.m_playbackOptions = updateData.m_playbackOptions;
			m_animations.PushBack( animationData );
		}
	}

	public const function HasAnimation( animName : CName ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( m_animations[ i ].m_animationName == animName )
			{
				return true;
			}
		}
		return false;
	}

	public function CleanAllAnimationsChachedData()
	{
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( m_animations[ i ].m_animProxy != NULL )
			{
				UnregisterAllCallbacks( m_animations[ i ] );
			}
		}
	}

	public function TriggerAnimations( owner : inkLogicController )
	{
		var currentProxy : inkAnimProxy;
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( !( IsNameValid( m_animations[ i ].m_animationName ) ) )
			{
				continue;
			}
			if( ( ( ( m_animations[ i ].m_animProxy == NULL ) || !( m_animations[ i ].m_lockWhenActive ) ) || m_animations[ i ].m_animProxy.IsFinished() ) || ( !( m_animations[ i ].m_animProxy.IsPaused() ) && !( m_animations[ i ].m_animProxy.IsPlaying() ) ) )
			{
				if( m_animations[ i ].m_animProxy != NULL )
				{
					UnregisterAllCallbacks( m_animations[ i ] );
				}
				currentProxy = owner.PlayLibraryAnimation( m_animations[ i ].m_animationName, m_animations[ i ].m_playbackOptions );
				m_animations[ i ].m_animProxy = currentProxy;
				RegisterAllCallbacks( owner, m_animations[ i ] );
			}
		}
	}

	public function TriggerAnimations( owner : inkGameController )
	{
		var currentProxy : inkAnimProxy;
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( !( IsNameValid( m_animations[ i ].m_animationName ) ) )
			{
				continue;
			}
			if( ( ( ( m_animations[ i ].m_animProxy == NULL ) || !( m_animations[ i ].m_lockWhenActive ) ) || m_animations[ i ].m_animProxy.IsFinished() ) || ( !( m_animations[ i ].m_animProxy.IsPaused() ) && !( m_animations[ i ].m_animProxy.IsPlaying() ) ) )
			{
				if( m_animations[ i ].m_animProxy != NULL )
				{
					UnregisterAllCallbacks( m_animations[ i ] );
				}
				currentProxy = owner.PlayLibraryAnimation( m_animations[ i ].m_animationName, m_animations[ i ].m_playbackOptions );
				m_animations[ i ].m_animProxy = currentProxy;
				RegisterAllCallbacks( owner, m_animations[ i ] );
			}
		}
	}

	public function TriggerAnimationByName( owner : inkLogicController, animName : CName, playbackOption : EInkAnimationPlaybackOption, optional targetWidget : inkWidget, optional playbackOptionsOverrideData : PlaybackOptionsUpdateData )
	{
		var currentProxy : inkAnimProxy;
		var playbackOptionsData : inkAnimOptions;
		var animData : SWidgetAnimationData;
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( !( IsNameValid( m_animations[ i ].m_animationName ) ) )
			{
				continue;
			}
			if( m_animations[ i ].m_animationName == animName )
			{
				if( playbackOption == EInkAnimationPlaybackOption.PLAY )
				{
					if( ( ( ( m_animations[ i ].m_animProxy == NULL ) || !( m_animations[ i ].m_lockWhenActive ) ) || m_animations[ i ].m_animProxy.IsFinished() ) || ( !( m_animations[ i ].m_animProxy.IsPaused() ) && !( m_animations[ i ].m_animProxy.IsPlaying() ) ) )
					{
						if( playbackOptionsOverrideData )
						{
							playbackOptionsData = playbackOptionsOverrideData.m_playbackOptions;
						}
						else
						{
							playbackOptionsData = m_animations[ i ].m_playbackOptions;
						}
						if( m_animations[ i ].m_animProxy != NULL )
						{
							ResolveActiveAnimDataPlaybackState( m_animations[ i ], EInkAnimationPlaybackOption.STOP );
						}
						if( targetWidget )
						{
							currentProxy = owner.PlayLibraryAnimationOnAutoSelectedTargets( m_animations[ i ].m_animationName, targetWidget, playbackOptionsData );
						}
						else
						{
							currentProxy = owner.PlayLibraryAnimation( m_animations[ i ].m_animationName, playbackOptionsData );
						}
						m_animations[ i ].m_animProxy = currentProxy;
						RegisterAllCallbacks( owner, m_animations[ i ] );
					}
				}
				else if( m_animations[ i ].m_animProxy != NULL )
				{
					animData = m_animations[ i ];
					if( playbackOptionsOverrideData )
					{
						animData.m_playbackOptions = playbackOptionsOverrideData.m_playbackOptions;
					}
					ResolveActiveAnimDataPlaybackState( animData, playbackOption );
				}
				break;
			}
		}
	}

	public function TriggerAnimationByName( owner : inkGameController, animName : CName, playbackOption : EInkAnimationPlaybackOption, optional targetWidget : inkWidget, optional playbackOptionsOverrideData : PlaybackOptionsUpdateData )
	{
		var currentProxy : inkAnimProxy;
		var playbackOptionsData : inkAnimOptions;
		var animData : SWidgetAnimationData;
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( !( IsNameValid( m_animations[ i ].m_animationName ) ) )
			{
				continue;
			}
			if( m_animations[ i ].m_animationName == animName )
			{
				if( playbackOption == EInkAnimationPlaybackOption.PLAY )
				{
					if( ( ( ( m_animations[ i ].m_animProxy == NULL ) || !( m_animations[ i ].m_lockWhenActive ) ) || m_animations[ i ].m_animProxy.IsFinished() ) || ( !( m_animations[ i ].m_animProxy.IsPaused() ) && !( m_animations[ i ].m_animProxy.IsPlaying() ) ) )
					{
						if( playbackOptionsOverrideData )
						{
							playbackOptionsData = playbackOptionsOverrideData.m_playbackOptions;
						}
						else
						{
							playbackOptionsData = m_animations[ i ].m_playbackOptions;
						}
						if( m_animations[ i ].m_animProxy != NULL )
						{
							ResolveActiveAnimDataPlaybackState( m_animations[ i ], EInkAnimationPlaybackOption.STOP );
						}
						if( targetWidget )
						{
							currentProxy = owner.PlayLibraryAnimationOnAutoSelectedTargets( m_animations[ i ].m_animationName, targetWidget, playbackOptionsData );
						}
						else
						{
							currentProxy = owner.PlayLibraryAnimation( m_animations[ i ].m_animationName, playbackOptionsData );
						}
						m_animations[ i ].m_animProxy = currentProxy;
						RegisterAllCallbacks( owner, m_animations[ i ] );
					}
				}
				else if( m_animations[ i ].m_animProxy != NULL )
				{
					animData = m_animations[ i ];
					if( playbackOptionsOverrideData )
					{
						animData.m_playbackOptions = playbackOptionsOverrideData.m_playbackOptions;
					}
					ResolveActiveAnimDataPlaybackState( animData, playbackOption );
				}
				break;
			}
		}
	}

	private function ResolveActiveAnimDataPlaybackState( const animData : ref< SWidgetAnimationData >, requestedState : EInkAnimationPlaybackOption )
	{
		if( animData.m_animProxy == NULL )
		{
			return;
		}
		if( requestedState == EInkAnimationPlaybackOption.STOP )
		{
			animData.m_animProxy.Stop( false );
			UnregisterAllCallbacks( animData );
		}
		else if( requestedState == EInkAnimationPlaybackOption.PAUSE )
		{
			animData.m_animProxy.Pause();
		}
		else if( requestedState == EInkAnimationPlaybackOption.RESUME )
		{
			animData.m_animProxy.Resume();
		}
		else if( requestedState == EInkAnimationPlaybackOption.CONTINUE )
		{
			animData.m_animProxy.Continue( animData.m_playbackOptions );
		}
		else if( requestedState == EInkAnimationPlaybackOption.GO_TO_START )
		{
			animData.m_animProxy.GotoStartAndStop( false );
			UnregisterAllCallbacks( animData );
		}
		else if( requestedState == EInkAnimationPlaybackOption.GO_TO_END )
		{
			animData.m_animProxy.GotoEndAndStop( false );
			UnregisterAllCallbacks( animData );
		}
	}

	public function UnregisterAllCallbacks( const animData : ref< SWidgetAnimationData > )
	{
		if( animData.m_animProxy != NULL )
		{
			if( IsNameValid( animData.m_onFinish ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnFinish );
			}
			if( IsNameValid( animData.m_onStart ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnStart );
			}
			if( IsNameValid( animData.m_onPasue ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnPause );
			}
			if( IsNameValid( animData.m_onResume ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnResume );
			}
			if( IsNameValid( animData.m_onStartLoop ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnStartLoop );
			}
			if( IsNameValid( animData.m_onEndLoop ) )
			{
				animData.m_animProxy.UnregisterFromAllCallbacks( inkanimEventType.OnEndLoop );
			}
		}
		CleanProxyData( animData );
	}

	public function RegisterAllCallbacks( owner : IScriptable, const animData : ref< SWidgetAnimationData > )
	{
		if( animData.m_animProxy != NULL )
		{
			if( IsNameValid( animData.m_onFinish ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, owner, animData.m_onFinish );
			}
			if( IsNameValid( animData.m_onStart ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnStart, owner, animData.m_onStart );
			}
			if( IsNameValid( animData.m_onPasue ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnPause, owner, animData.m_onPasue );
			}
			if( IsNameValid( animData.m_onResume ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnResume, owner, animData.m_onResume );
			}
			if( IsNameValid( animData.m_onStartLoop ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnStartLoop, owner, animData.m_onStartLoop );
			}
			if( IsNameValid( animData.m_onEndLoop ) )
			{
				animData.m_animProxy.RegisterToCallback( inkanimEventType.OnEndLoop, owner, animData.m_onEndLoop );
			}
		}
	}

	public function ResolveCallback( owner : IScriptable, animProxy : inkAnimProxy, eventType : inkanimEventType )
	{
		var i : Int32;
		if( animProxy == NULL )
		{
			return;
		}
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( m_animations[ i ].m_animProxy == animProxy )
			{
				if( eventType == inkanimEventType.OnFinish )
				{
					UnregisterAllCallbacks( m_animations[ i ] );
					m_animations[ i ].m_animProxy = NULL;
				}
				else
				{
					animProxy.UnregisterFromCallback( eventType, owner, GetAnimationCallbackName( m_animations[ i ], eventType ) );
				}
			}
		}
	}

	private function GetAnimationCallbackName( const animData : ref< SWidgetAnimationData >, eventType : inkanimEventType ) : CName
	{
		var returnValue : CName;
		if( eventType == inkanimEventType.OnStart )
		{
			animData.m_onStart;
		}
		else if( eventType == inkanimEventType.OnFinish )
		{
			animData.m_onFinish;
		}
		else if( eventType == inkanimEventType.OnPause )
		{
			animData.m_onPasue;
		}
		else if( eventType == inkanimEventType.OnResume )
		{
			animData.m_onResume;
		}
		else if( eventType == inkanimEventType.OnStartLoop )
		{
			animData.m_onStartLoop;
		}
		else if( eventType == inkanimEventType.OnEndLoop )
		{
			animData.m_onEndLoop;
		}
		return returnValue;
	}

	private function CleanProxyData( const animData : ref< SWidgetAnimationData > )
	{
		var i : Int32;
		for( i = 0; i < m_animations.Size(); i += 1 )
		{
			if( m_animations[ i ].m_animProxy == animData.m_animProxy )
			{
				m_animations[ i ].m_animProxy = NULL;
				break;
			}
		}
	}

}

