import class gameuiPhotoModeStickersController extends inkGameController
{
	public import function OnStickerTransformChanged( stickerIndex : Int32, stickerPosition : Vector2, stickerScale : Float, stickerRotation : Float );
	public import function OnMouseHover( stickerIndex : Int32 );

	private editable var m_stickerLibraryId : CName;
	private editable var m_stickersRoot : inkWidgetRef;
	private editable var m_frameRoot : inkWidgetRef;
	private editable var m_backgroundViewRoot : inkWidgetRef;
	private var m_stickers : array< weak< inkWidget > >;
	private var m_frame : weak< inkWidget >;
	private var m_frameLogic : weak< PhotoModeFrame >;
	private var m_currentHovered : Int32;
	private var m_currentMouseDrag : Int32;
	private var m_currentMouseRotate : Int32;
	private var m_stickerDragStartRotation : Float;
	private var m_stickerDragStartScale : Vector2;
	private var m_stickerDragStartPos : Vector2;
	private var m_mouseDragStartPos : Vector2;
	private var m_mouseDragCurrentPos : Vector2;
	private var m_currentSticker : Int32;
	private var m_stickerMove : Vector2;
	private var m_stickerRotation : Float;
	private var m_stickerScale : Float;
	private var m_stickersAreaSize : Vector2;
	private var m_cursorInputEnabled : Bool;
	private var m_editorEnabled : Bool;
	private var m_root : weak< inkCanvas >;
	private var m_isInPhotoMode : Bool;

	protected event OnInitialize()
	{
		m_root = ( ( inkCanvas )( GetRootWidget() ) );
		m_stickersAreaSize = m_root.GetSize();
		ResetState();
		m_editorEnabled = false;
		m_isInPhotoMode = false;
		RegisterToCallback( 'OnResetStickers', this, 'OnResetStickers' );
		RegisterToCallback( 'OnSetStickerImage', this, 'OnSetStickerImage' );
		RegisterToCallback( 'OnSetSetSelectedSticker', this, 'OnSetSetSelectedSticker' );
		RegisterToCallback( 'OnSetFrameImage', this, 'OnSetFrameImage' );
		RegisterToCallback( 'OnSetBackground', this, 'OnSetBackground' );
	}

	protected function ResetState()
	{
		m_currentSticker = -1;
		m_currentHovered = -1;
		m_currentMouseDrag = -1;
		m_currentMouseRotate = -1;
		m_stickerDragStartRotation = 0.0;
		m_cursorInputEnabled = true;
	}

	protected event OnUninitialize()
	{
		UnregisterFromCallback( 'OnResetStickers', this, 'OnResetStickers' );
		UnregisterFromCallback( 'OnSetStickerImage', this, 'OnSetStickerImage' );
		UnregisterFromCallback( 'OnSetSetSelectedSticker', this, 'OnSetSetSelectedSticker' );
		UnregisterFromCallback( 'OnSetFrameImage', this, 'OnSetFrameImage' );
		UnregisterFromCallback( 'OnSetBackground', this, 'OnSetBackground' );
	}

	protected event OnEnterPhotoMode()
	{
		var slotsCount : Int32;
		var i : Int32;
		slotsCount = TDB.GetInt( T"photo_mode.stickers.stickerSlotsCount", 10 );
		for( i = 0; i < slotsCount; i += 1 )
		{
			AddSticker();
		}
		ResetState();
		m_isInPhotoMode = true;
	}

	protected event OnExitPhotomode()
	{
		var i : Int32;
		var stickersRootCompund : weak< inkCompoundWidget >;
		var frameRootCompund : weak< inkCompoundWidget >;
		m_isInPhotoMode = false;
		stickersRootCompund = ( ( inkCompoundWidget )( inkWidgetRef.Get( m_stickersRoot ) ) );
		for( i = 0; i < m_stickers.Size(); i += 1 )
		{
			stickersRootCompund.RemoveChild( m_stickers[ i ] );
		}
		m_stickers.Clear();
		if( m_frame != NULL )
		{
			frameRootCompund = ( ( inkCompoundWidget )( inkWidgetRef.Get( m_frameRoot ) ) );
			frameRootCompund.RemoveChild( m_frame );
			m_frame = NULL;
			m_frameLogic = NULL;
		}
		inkWidgetRef.SetVisible( m_backgroundViewRoot, false );
		ResetState();
	}

	protected event OnEnableStickerEditor()
	{
		m_editorEnabled = true;
		m_stickersAreaSize = m_root.GetSize();
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnStickersButtonRelease' );
		RegisterToGlobalInputCallback( 'OnPostOnHold', this, 'OnStickersButtonHold' );
		RegisterToGlobalInputCallback( 'OnPostOnPress', this, 'OnStickersButtonPress' );
		RegisterToGlobalInputCallback( 'OnPostOnAxis', this, 'OnStickersAxisInput' );
	}

	protected event OnDisableStickerEditor()
	{
		m_editorEnabled = false;
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnStickersButtonRelease' );
		UnregisterFromGlobalInputCallback( 'OnPostOnHold', this, 'OnStickersButtonHold' );
		UnregisterFromGlobalInputCallback( 'OnPostOnPress', this, 'OnStickersButtonPress' );
		UnregisterFromGlobalInputCallback( 'OnPostOnAxis', this, 'OnStickersAxisInput' );
		ResetStickerCursorState();
	}

	protected function ResetStickerCursorState()
	{
		if( m_currentMouseDrag >= 0 )
		{
			m_stickers[ m_currentMouseDrag ].SetOpacity( 1.0 );
			m_currentMouseDrag = -1;
		}
		if( m_currentMouseRotate >= 0 )
		{
			m_stickers[ m_currentMouseRotate ].SetOpacity( 1.0 );
			m_currentMouseRotate = -1;
		}
		if( m_currentHovered >= 0 )
		{
			m_stickers[ m_currentHovered ].SetOpacity( 1.0 );
			m_currentHovered = -1;
			OnMouseHover( m_currentHovered );
		}
	}

	protected event OnCursorInputEnabled( enable : Bool )
	{
		if( !( enable ) )
		{
			ResetStickerCursorState();
		}
		m_cursorInputEnabled = enable;
	}

	protected event OnStickersButtonRelease( e : inkPointerEvent )
	{
		var opacity : Float;
		opacity = ( ( m_currentHovered == -1 ) ? ( 1.0 ) : ( 0.64999998 ) );
		if( m_cursorInputEnabled && m_editorEnabled )
		{
			if( e.IsAction( 'PhotoMode_CameraMouseMove' ) )
			{
				if( m_currentMouseDrag >= 0 )
				{
					m_stickers[ m_currentMouseDrag ].SetOpacity( opacity );
					m_currentMouseDrag = -1;
				}
			}
			if( e.IsAction( 'PhotoMode_CameraMouseRotation' ) )
			{
				if( m_currentMouseRotate >= 0 )
				{
					m_stickers[ m_currentMouseRotate ].SetOpacity( opacity );
					m_currentMouseRotate = -1;
				}
			}
		}
	}

	protected event OnStickersButtonHold( e : inkPointerEvent )
	{
		if( m_cursorInputEnabled && m_editorEnabled )
		{
			if( e.IsAction( 'PhotoMode_CameraMouseMove' ) )
			{
				if( m_currentMouseDrag >= 0 )
				{
					m_mouseDragCurrentPos = e.GetScreenSpacePosition();
				}
			}
			if( e.IsAction( 'PhotoMode_CameraMouseRotation' ) )
			{
				if( m_currentMouseRotate >= 0 )
				{
					m_mouseDragCurrentPos = e.GetScreenSpacePosition();
				}
			}
		}
	}

	protected event OnStickersButtonPress( e : inkPointerEvent )
	{
		var margin : inkMargin;
		if( m_cursorInputEnabled && m_editorEnabled )
		{
			if( m_currentHovered >= 0 )
			{
				if( e.IsAction( 'PhotoMode_CameraMouseMove' ) )
				{
					if( ( m_currentMouseDrag == -1 ) && ( m_currentMouseRotate == -1 ) )
					{
						m_currentMouseDrag = m_currentHovered;
						m_mouseDragStartPos = e.GetScreenSpacePosition();
						m_mouseDragCurrentPos = e.GetScreenSpacePosition();
						margin = m_stickers[ m_currentMouseDrag ].GetMargin();
						m_stickerDragStartPos.X = margin.left;
						m_stickerDragStartPos.Y = margin.top;
					}
				}
				if( e.IsAction( 'PhotoMode_CameraMouseRotation' ) )
				{
					if( ( m_currentMouseDrag == -1 ) && ( m_currentMouseRotate == -1 ) )
					{
						m_currentMouseRotate = m_currentHovered;
						m_mouseDragStartPos = e.GetScreenSpacePosition();
						m_mouseDragCurrentPos = e.GetScreenSpacePosition();
						m_stickerDragStartRotation = m_stickers[ m_currentMouseRotate ].GetRotation();
						m_stickerDragStartScale = m_stickers[ m_currentMouseRotate ].GetScale();
						margin = m_stickers[ m_currentMouseRotate ].GetMargin();
						m_stickerDragStartPos.X = margin.left;
						m_stickerDragStartPos.Y = margin.top;
					}
				}
			}
		}
	}

	protected event OnStickersAxisInput( e : inkPointerEvent )
	{
		var amount : Float;
		if( m_currentSticker >= 0 )
		{
			amount = e.GetAxisData();
			if( e.IsAction( 'PhotoMode_CameraMovementX' ) )
			{
				m_stickerMove.X += amount;
			}
			else if( e.IsAction( 'PhotoMode_CameraMovementY' ) )
			{
				m_stickerMove.Y -= amount;
			}
			else if( e.IsAction( 'PhotoMode_CameraRotationX' ) )
			{
				m_stickerRotation += amount;
			}
			else if( e.IsAction( 'PhotoMode_CraneUp' ) )
			{
				m_stickerScale += amount;
			}
			else if( e.IsAction( 'PhotoMode_CraneDown' ) )
			{
				m_stickerScale -= amount;
			}
		}
	}

	protected function DiffAngle( a : Float, b : Float ) : Float
	{
		var diff : Float;
		diff = b - a;
		while( diff < -180.0 )
		{
			diff += 360.0;
		}
		while( diff > 180.0 )
		{
			diff -= 360.0;
		}
		return diff;
	}

	protected function RotateScaleSticker( sticker : inkWidget )
	{
		var cursorPos : Vector2;
		var cursorStartPos : Vector2;
		var rootScale : Vector2;
		var offset : Vector4;
		var startOffset : Vector4;
		var angle : Float;
		var startAngle : Float;
		var scale : Float;
		rootScale = GetRootWidget().GetScale();
		cursorPos.X = ( m_mouseDragCurrentPos.X / rootScale.X ) - ( m_stickersAreaSize.X * 0.5 );
		cursorPos.Y = ( m_mouseDragCurrentPos.Y / rootScale.Y ) - ( m_stickersAreaSize.Y * 0.5 );
		cursorStartPos.X = ( m_mouseDragStartPos.X / rootScale.X ) - ( m_stickersAreaSize.X * 0.5 );
		cursorStartPos.Y = ( m_mouseDragStartPos.Y / rootScale.Y ) - ( m_stickersAreaSize.Y * 0.5 );
		offset.X = cursorPos.X - m_stickerDragStartPos.X;
		offset.Y = cursorPos.Y - m_stickerDragStartPos.Y;
		offset.Z = offset.W = 0.0;
		startOffset.X = cursorStartPos.X - m_stickerDragStartPos.X;
		startOffset.Y = cursorStartPos.Y - m_stickerDragStartPos.Y;
		startOffset.Z = startOffset.W = 0.0;
		angle = Rad2Deg( -( AtanF( -( offset.Y ), offset.X ) ) );
		startAngle = Rad2Deg( -( AtanF( -( startOffset.Y ), startOffset.X ) ) );
		scale = m_stickerDragStartScale.X * ( Vector4.Length( offset ) / Vector4.Length( startOffset ) );
		scale = ClampF( scale, 0.5, 1.5 );
		sticker.SetRotation( m_stickerDragStartRotation + DiffAngle( startAngle, angle ) );
		sticker.SetScale( Vector2( scale, scale ) );
	}

	protected event OnForceStickerTransform( stickerIndex : Int32, position : Vector2, scale : Float, rotation : Float )
	{
		var margin : inkMargin;
		margin = m_stickers[ stickerIndex ].GetMargin();
		margin.left = position.X;
		margin.top = position.Y;
		m_stickers[ stickerIndex ].SetMargin( margin );
		m_stickers[ stickerIndex ].SetRotation( rotation );
		m_stickers[ stickerIndex ].SetScale( Vector2( scale, scale ) );
		OnStickerTransformChanged( stickerIndex, position, scale, rotation );
	}

	protected event OnUpdateStickers( timeDelta : Float )
	{
		var rootScale : Vector2;
		var margin : inkMargin;
		var rotation : Float;
		var scale : Vector2;
		var sticker : inkWidget;
		if( m_isInPhotoMode )
		{
			rootScale = GetRootWidget().GetScale();
			if( m_currentMouseRotate >= 0 )
			{
				sticker = m_stickers[ m_currentMouseRotate ];
				RotateScaleSticker( sticker );
				margin = sticker.GetMargin();
				rotation = sticker.GetRotation();
				scale = sticker.GetScale();
				OnStickerTransformChanged( m_currentMouseRotate, Vector2( margin.left, margin.top ), scale.X, rotation );
			}
			else if( m_currentMouseDrag >= 0 )
			{
				sticker = m_stickers[ m_currentMouseDrag ];
				margin = sticker.GetMargin();
				rotation = sticker.GetRotation();
				scale = sticker.GetScale();
				margin.left = m_stickerDragStartPos.X + ( ( m_mouseDragCurrentPos.X - m_mouseDragStartPos.X ) / rootScale.X );
				margin.top = m_stickerDragStartPos.Y + ( ( m_mouseDragCurrentPos.Y - m_mouseDragStartPos.Y ) / rootScale.Y );
				margin.left = ClampF( margin.left, -( m_stickersAreaSize.X ) * 0.5, m_stickersAreaSize.X * 0.5 );
				margin.top = ClampF( margin.top, -( m_stickersAreaSize.Y ) * 0.5, m_stickersAreaSize.Y * 0.5 );
				sticker.SetMargin( margin );
				OnStickerTransformChanged( m_currentMouseDrag, Vector2( margin.left, margin.top ), scale.X, rotation );
			}
			else if( m_currentSticker >= 0 )
			{
				sticker = m_stickers[ m_currentSticker ];
				margin = sticker.GetMargin();
				rotation = sticker.GetRotation();
				scale = sticker.GetScale();
				margin.left += ( ( m_stickerMove.X * timeDelta ) * 1500.0 );
				margin.top += ( ( m_stickerMove.Y * timeDelta ) * 1500.0 );
				margin.left = ClampF( margin.left, -( m_stickersAreaSize.X ) * 0.5, m_stickersAreaSize.X * 0.5 );
				margin.top = ClampF( margin.top, -( m_stickersAreaSize.Y ) * 0.5, m_stickersAreaSize.Y * 0.5 );
				rotation += ( ( m_stickerRotation * timeDelta ) * 100.0 );
				scale.X += ( ( m_stickerScale * timeDelta ) * 2.0 );
				scale.Y += ( ( m_stickerScale * timeDelta ) * 2.0 );
				scale.X = ClampF( scale.X, 0.5, 1.5 );
				scale.Y = ClampF( scale.Y, 0.5, 1.5 );
				sticker.SetMargin( margin );
				sticker.SetRotation( rotation );
				sticker.SetScale( scale );
				OnStickerTransformChanged( m_currentSticker, Vector2( margin.left, margin.top ), scale.X, rotation );
				m_stickerMove.X = 0.0;
				m_stickerMove.Y = 0.0;
				m_stickerRotation = 0.0;
				m_stickerScale = 0.0;
			}
			if( m_frameLogic )
			{
				m_frameLogic.Update( timeDelta );
			}
		}
	}

	protected event OnSetSetSelectedSticker( stickerIndex : Int32 )
	{
		if( stickerIndex >= 0 )
		{
			m_currentSticker = ( ( Int32 )( stickerIndex ) );
		}
		else
		{
			m_currentSticker = -1;
		}
	}

	protected event OnSetStickerImage( stickerIndex : Uint32, atlasPath : ResRef, imagePart : CName, imageIndex : Int32 )
	{
		var i : Int32;
		var sticker : PhotoModeSticker;
		i = ( ( Int32 )( stickerIndex ) );
		if( imagePart == '' || !( ResRef.IsValid( atlasPath ) ) )
		{
			m_stickers[ ( ( Int32 )( stickerIndex ) ) ].SetVisible( false );
		}
		else
		{
			m_stickers[ i ].SetVisible( true );
		}
		sticker = ( ( PhotoModeSticker )( m_stickers[ i ].GetControllerByType( 'PhotoModeSticker' ) ) );
		sticker.SetAtlas( atlasPath );
		sticker.SetImage( imagePart );
	}

	protected event OnResetStickers()
	{
		var i : Int32;
		for( i = 0; i < m_stickers.Size(); i += 1 )
		{
			m_stickers[ i ].SetVisible( false );
			m_stickers[ i ].SetOpacity( 1.0 );
			m_stickers[ i ].SetMargin( 0.0, 0.0, 0.0, 0.0 );
			m_stickers[ i ].SetRotation( 0.0 );
			m_stickers[ i ].SetScale( Vector2( 1.0, 1.0 ) );
		}
		m_currentSticker = -1;
		m_currentHovered = -1;
		m_currentMouseDrag = -1;
		m_currentMouseRotate = -1;
		OnMouseHover( m_currentHovered );
	}

	protected event OnSetFrameImage( atlasPath : ResRef, imageParts : array< CName >, libraryItemName : CName, color : Color, flipHorizontal : Bool, flipVertical : Bool )
	{
		var frameRootCompund : weak< inkCompoundWidget >;
		if( m_frame != NULL )
		{
			frameRootCompund = ( ( inkCompoundWidget )( inkWidgetRef.Get( m_frameRoot ) ) );
			frameRootCompund.RemoveChild( m_frame );
			m_frame = NULL;
			m_frameLogic = NULL;
		}
		if( ( imageParts.Size() > 0 ) && ResRef.IsValid( atlasPath ) )
		{
			m_frame = AddFrame( libraryItemName );
			m_frameLogic = ( ( PhotoModeFrame )( m_frame.GetControllerByType( 'PhotoModeFrame' ) ) );
			m_frameLogic.SetupScale( m_stickersAreaSize );
			m_frameLogic.SetAtlas( atlasPath );
			m_frameLogic.SetImages( imageParts );
			m_frameLogic.SetColor( color );
			m_frameLogic.SetFlip( flipHorizontal, flipVertical );
		}
	}

	protected event OnSetBackground( enabled : Bool )
	{
		var animDef : inkAnimDef;
		var animInterp : inkAnimTransparency;
		if( enabled && !( inkWidgetRef.IsVisible( m_backgroundViewRoot ) ) )
		{
			inkWidgetRef.SetOpacity( m_backgroundViewRoot, 0.0 );
			animDef = new inkAnimDef;
			animInterp = new inkAnimTransparency;
			animInterp.SetStartTransparency( 0.0 );
			animInterp.SetEndTransparency( 1.0 );
			animInterp.SetDuration( 0.40000001 );
			animInterp.SetDirection( inkanimInterpolationDirection.To );
			animInterp.SetUseRelativeDuration( true );
			animDef.AddInterpolator( animInterp );
			inkWidgetRef.PlayAnimation( m_backgroundViewRoot, animDef );
		}
		inkWidgetRef.SetVisible( m_backgroundViewRoot, enabled );
	}

	protected function AddSticker()
	{
		var newSticker : weak< inkWidget >;
		var stickerLogic : PhotoModeSticker;
		var margin : inkMargin;
		newSticker = SpawnFromLocal( inkWidgetRef.Get( m_stickersRoot ), m_stickerLibraryId );
		newSticker.SetAnchorPoint( 0.5, 0.5 );
		newSticker.SetAnchor( inkEAnchor.Centered );
		newSticker.SetVisible( false );
		margin = newSticker.GetMargin();
		margin.left = -( m_stickersAreaSize.X ) * 0.25;
		newSticker.SetMargin( margin );
		stickerLogic = ( ( PhotoModeSticker )( newSticker.GetControllerByType( 'PhotoModeSticker' ) ) );
		stickerLogic.m_stickersController = this;
		m_stickers.PushBack( newSticker );
	}

	protected function AddFrame( libraryItem : CName ) : weak< inkWidget >
	{
		m_frame = SpawnFromLocal( inkWidgetRef.Get( m_frameRoot ), libraryItem );
		m_frame.SetAnchorPoint( 0.5, 0.5 );
		m_frame.SetAnchor( inkEAnchor.Fill );
		m_frame.SetVisible( true );
		m_frame.SetOpacity( 0.0 );
		return m_frame;
	}

	public function StickerHoveredOutByMouse( sticker : weak< inkWidget > )
	{
		var i : Int32;
		if( m_cursorInputEnabled && m_editorEnabled )
		{
			for( i = 0; i < m_stickers.Size(); i += 1 )
			{
				if( ( m_stickers[ i ] == sticker ) && ( m_currentHovered == i ) )
				{
					SetCursorContext( 'Default' );
					if( ( m_currentMouseRotate == -1 ) && ( m_currentMouseDrag == -1 ) )
					{
						m_stickers[ i ].SetOpacity( 1.0 );
					}
					m_currentHovered = -1;
					OnMouseHover( m_currentHovered );
					break;
				}
			}
		}
	}

	public function StickerHoveredByMouse( sticker : weak< inkWidget > )
	{
		var i : Int32;
		if( ( ( m_cursorInputEnabled && m_editorEnabled ) && ( m_currentMouseRotate == -1 ) ) && ( m_currentMouseDrag == -1 ) )
		{
			if( m_currentHovered >= 0 )
			{
				m_stickers[ m_currentHovered ].SetOpacity( 1.0 );
				m_currentHovered = -1;
			}
			for( i = 0; i < m_stickers.Size(); i += 1 )
			{
				if( m_stickers[ i ] == sticker )
				{
					SetCursorContext( 'Hover' );
					m_stickers[ i ].SetOpacity( 0.64999998 );
					m_currentHovered = i;
					break;
				}
			}
			OnMouseHover( m_currentHovered );
		}
	}

}

