class scannerBorderLogicController extends inkLogicController
{
	private const editable var m_braindanceSetVisible : array< inkWidgetRef >;
	private const editable var m_braindanceSetHidden : array< inkWidgetRef >;

	public function SetBraindanceMode( isBraindance : Bool )
	{
		var i : Int32;
		for( i = 0; i < m_braindanceSetVisible.Size(); i += 1 )
		{
			inkWidgetRef.SetVisible( m_braindanceSetVisible[ i ], isBraindance );
		}
		for( i = 0; i < m_braindanceSetHidden.Size(); i += 1 )
		{
			inkWidgetRef.SetVisible( m_braindanceSetHidden[ i ], !( isBraindance ) );
		}
	}

}

class scannerBorderGameController extends inkProjectedHUDGameController
{
	private editable var m_ZoomMovingContainer : inkCompoundRef;
	private editable var m_DistanceMovingContainer : inkCompoundRef;
	private editable var m_DistanceParentContainer : inkCompoundRef;
	private editable var m_CrosshairProjection : inkCompoundRef;
	private editable var m_loadingBarCanvas : inkCompoundRef;
	private editable var m_crosshairContainer : inkCompoundRef;
	private editable var m_ZoomNumber : inkTextRef;
	private editable var m_DistanceNumber : inkTextRef;
	private editable var m_DistanceImageRuler : inkImageRef;
	private editable var m_ZoomMoveBracketL : inkImageRef;
	private editable var m_ZoomMoveBracketR : inkImageRef;
	private editable var m_scannerBarWidget : inkCompoundRef;
	private editable var m_scannerBarFluffText : inkTextRef;
	private editable var m_scannerBarFill : inkImageRef;
	private const editable var m_deviceFluffs : array< inkWidgetRef >;
	private var m_LockOnAnimProxy : inkAnimProxy;
	private var m_IdleAnimProxy : inkAnimProxy;
	private var m_BracketsAppearAnimProxy : inkAnimProxy;
	private var lockOutAnimWasPlayed : Bool;
	private var m_root : weak< inkCompoundWidget >;
	private var m_currentTarget : EntityID;
	private var m_isTakeControllActive : Bool;
	private var m_ownerObject : weak< GameObject >;
	private var m_currentTargetBuffered : EntityID;
	private var m_scannerData : scannerDataStructure;
	private var m_shouldShowScanner : Bool;
	private var m_isFullyScanned : Bool;
	private var m_ProjectionLogicController : weak< ScannerCrosshairLogicController >;
	private var m_OriginalScannerBarFillSize : Vector2;
	private var zoomUpAnim : inkAnimProxy;
	private var animLockOn : inkAnimProxy;
	private var zoomDownAnim : inkAnimProxy;
	private var animLockOff : inkAnimProxy;
	private var m_exclusiveFocusAnim : inkAnimProxy;
	private var m_isExclusiveFocus : Bool;
	private var argZoomBuffered : Float;
	private var m_squares : array< weak< inkImage > >;
	private var m_squaresFilled : array< weak< inkImage > >;
	private var m_scanBlackboard : weak< IBlackboard >;
	private var m_psmBlackboard : weak< IBlackboard >;
	private var m_tcsBlackboard : weak< IBlackboard >;
	private var m_BBID_ScanObject : CallbackHandle;
	private var m_BBID_ScanObject_Data : CallbackHandle;
	private var m_BBID_ScanObject_Position : CallbackHandle;
	private var m_BBID_ScanState : CallbackHandle;
	private var m_BBID_ProgressNum : CallbackHandle;
	private var m_BBID_ProgressText : CallbackHandle;
	private var m_BBID_ExclusiveFocus : CallbackHandle;
	private var m_PSM_BBID : CallbackHandle;
	private var m_tcs_BBID : CallbackHandle;
	private var m_VisionStateBlackboardId : CallbackHandle;

	protected event OnInitialize()
	{
		var i : Int32;
		m_ownerObject = ( ( GameObject )( GetOwnerEntity() ) );
		m_scanBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Scanner );
		if( m_scanBlackboard )
		{
			m_BBID_ScanObject = m_scanBlackboard.RegisterDelayedListenerEntityID( GetAllBlackboardDefs().UI_Scanner.ScannedObject, this, 'OnScannedObject', true );
			m_BBID_ScanObject_Data = m_scanBlackboard.RegisterDelayedListenerVariant( GetAllBlackboardDefs().UI_Scanner.scannerObjectStats, this, 'OnScannerObjectStats', true );
			m_BBID_ScanObject_Position = m_scanBlackboard.RegisterDelayedListenerFloat( GetAllBlackboardDefs().UI_Scanner.scannerObjectDistance, this, 'OnObjectPositionChange', true );
			m_BBID_ScanState = m_scanBlackboard.RegisterDelayedListenerVariant( GetAllBlackboardDefs().UI_Scanner.CurrentState, this, 'OnStateChanged', true );
			m_BBID_ProgressNum = m_scanBlackboard.RegisterDelayedListenerFloat( GetAllBlackboardDefs().UI_Scanner.CurrentProgress, this, 'OnProgressChange', true );
			m_BBID_ProgressText = m_scanBlackboard.RegisterDelayedListenerString( GetAllBlackboardDefs().UI_Scanner.ProgressBarText, this, 'OnProgressBarFluffTextChange', true );
			m_BBID_ExclusiveFocus = m_scanBlackboard.RegisterDelayedListenerBool( GetAllBlackboardDefs().UI_Scanner.exclusiveFocusActive, this, 'OnExclusiveFocus', true );
		}
		m_tcsBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().DeviceTakeControl );
		if( m_tcsBlackboard )
		{
			m_tcs_BBID = m_tcsBlackboard.RegisterDelayedListenerEntityID( GetAllBlackboardDefs().DeviceTakeControl.ActiveDevice, this, 'OnChangeControlledDevice' );
			OnChangeControlledDevice( m_tcsBlackboard.GetEntityID( GetAllBlackboardDefs().DeviceTakeControl.ActiveDevice ) );
		}
		m_root = ( ( inkCompoundWidget )( GetRootWidget() ) );
		inkCompoundRef.SetVisible( m_scannerBarWidget, false );
		if( inkCompoundRef.Get( m_CrosshairProjection ) )
		{
			m_ProjectionLogicController = ( ( ScannerCrosshairLogicController )( inkCompoundRef.Get( m_CrosshairProjection ).GetController() ) );
		}
		if( m_ProjectionLogicController )
		{
			m_ProjectionLogicController.SetProjection( RegisterScreenProjection( m_ProjectionLogicController.CreateProjectionData() ) );
		}
		for( i = 0; i < 14; i += 1 )
		{
			m_squares.PushBack( ( ( inkImage )( GetWidget( StringToName( "scanner_overlay\scannerDots\dot" + IntToString( i + 1 ) ) ) ) ) );
		}
	}

	protected event OnUninitialize()
	{
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.ScannedObject, m_BBID_ScanObject );
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.scannerObjectStats, m_BBID_ScanObject_Data );
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.scannerObjectDistance, m_BBID_ScanObject_Position );
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.CurrentState, m_BBID_ScanState );
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.CurrentProgress, m_BBID_ProgressNum );
		m_scanBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_Scanner.ProgressBarText, m_BBID_ProgressText );
		if( m_tcsBlackboard )
		{
			m_tcsBlackboard.UnregisterListenerEntityID( GetAllBlackboardDefs().DeviceTakeControl.ActiveDevice, m_tcs_BBID );
		}
	}

	protected event OnPlayerAttach( playerPuppet : GameObject )
	{
		m_psmBlackboard = GetPSMBlackboard( playerPuppet );
		if( m_psmBlackboard )
		{
			m_PSM_BBID = m_psmBlackboard.RegisterDelayedListenerFloat( GetAllBlackboardDefs().PlayerStateMachine.ZoomLevel, this, 'OnScannerZoom' );
			m_VisionStateBlackboardId = m_psmBlackboard.RegisterListenerInt( GetAllBlackboardDefs().PlayerStateMachine.Vision, this, 'OnPSMVisionStateChanged' );
		}
	}

	protected event OnPlayerDetach( playerPuppet : GameObject )
	{
		m_psmBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().PlayerStateMachine.ZoomLevel, m_PSM_BBID );
		m_psmBlackboard.UnregisterListenerInt( GetAllBlackboardDefs().PlayerStateMachine.Vision, m_VisionStateBlackboardId );
	}

	protected event OnChangeControlledDevice( value : EntityID )
	{
		m_isTakeControllActive = EntityID.IsDefined( value );
		ResolveState();
	}

	private function ResolveState()
	{
		var stateName : CName;
		var i : Int32;
		if( m_isTakeControllActive )
		{
			stateName = 'Device';
		}
		else
		{
			stateName = 'Default';
		}
		for( i = 0; i < m_deviceFluffs.Size(); i += 1 )
		{
			inkWidgetRef.SetState( m_deviceFluffs[ i ], stateName );
		}
	}

	public function PlayLockAnimation( showAnim : Bool )
	{
		var idleAnimOptions : inkAnimOptions;
		if( !( m_isExclusiveFocus ) )
		{
			idleAnimOptions.toMarker = 'stop';
			animLockOff.Stop();
			animLockOn.Stop();
			if( showAnim )
			{
				animLockOn = PlayLibraryAnimation( 'LockOnAnim', idleAnimOptions );
			}
			if( !( showAnim ) )
			{
				animLockOff = PlayLibraryAnimation( 'LockOffAnim', idleAnimOptions );
			}
		}
	}

	private function ComputeVisibility()
	{
		var owner : GameObject;
		var currentTargetObject : weak< GameObject >;
		if( !( EntityID.IsDefined( m_currentTarget ) ) )
		{
			m_ProjectionLogicController.SetEntity( NULL );
			inkCompoundRef.SetVisible( m_DistanceParentContainer, false );
			inkCompoundRef.SetVisible( m_CrosshairProjection, false );
			PlayLockAnimation( false );
			return;
		}
		owner = ( ( GameObject )( GetOwnerEntity() ) );
		currentTargetObject = ( ( GameObject )( GameInstance.FindEntityByID( owner.GetGame(), m_currentTarget ) ) );
		if( ShouldShowScanner( currentTargetObject ) )
		{
			m_ProjectionLogicController.SetEntity( currentTargetObject );
			inkCompoundRef.SetVisible( m_DistanceParentContainer, true );
			inkCompoundRef.SetVisible( m_CrosshairProjection, true );
			PlayLockAnimation( true );
		}
		else
		{
			m_ProjectionLogicController.SetEntity( NULL );
			inkCompoundRef.SetVisible( m_DistanceParentContainer, false );
			inkCompoundRef.SetVisible( m_CrosshairProjection, false );
			PlayLockAnimation( false );
		}
	}

	protected event OnScreenProjectionUpdate( projections : gameuiScreenProjectionsData )
	{
		var i : Int32;
		var currData : weak< ScannerCrosshairLogicController >;
		for( i = 0; i < projections.data.Size(); i += 1 )
		{
			currData = ( ( ScannerCrosshairLogicController )( projections.data[ i ].GetUserData() ) );
			if( currData != NULL )
			{
				currData.UpdateProjection();
			}
		}
	}

	protected event OnObjectPositionChange( pos : Float )
	{
		inkTextRef.SetText( m_DistanceNumber, FloatToStringPrec( pos, 1 ) );
	}

	protected event OnPSMVisionStateChanged( value : Int32 )
	{
		var newState : gamePSMVision;
		newState = ( ( gamePSMVision )( value ) );
		if( newState != gamePSMVision.Focus )
		{
			inkCompoundRef.SetVisible( m_loadingBarCanvas, false );
			inkCompoundRef.SetVisible( m_crosshairContainer, true );
		}
	}

	protected event OnExclusiveFocus( isExclusiveFocus : Bool )
	{
		var animOption : inkAnimOptions;
		m_isExclusiveFocus = isExclusiveFocus;
		inkCompoundRef.SetVisible( m_loadingBarCanvas, m_isExclusiveFocus );
		inkCompoundRef.SetVisible( m_crosshairContainer, !( m_isExclusiveFocus ) );
		if( inkCompoundRef.Get( m_crosshairContainer ) )
		{
			if( m_isExclusiveFocus )
			{
				inkCompoundRef.SetState( m_crosshairContainer, 'Animated' );
			}
			else
			{
				inkCompoundRef.SetState( m_crosshairContainer, 'Default' );
			}
		}
		if( !( m_isExclusiveFocus ) )
		{
			if( animLockOn )
			{
				animLockOn.Stop();
				animLockOn = NULL;
			}
			if( animLockOff )
			{
				animLockOff.Stop();
				animLockOff = NULL;
			}
			if( m_exclusiveFocusAnim )
			{
				m_exclusiveFocusAnim.Stop();
				m_exclusiveFocusAnim = NULL;
			}
		}
		else
		{
			if( !( m_exclusiveFocusAnim ) )
			{
				animOption.loopType = inkanimLoopType.PingPong;
				animOption.loopInfinite = true;
				m_exclusiveFocusAnim = PlayLibraryAnimation( 'loadingBar', animOption );
			}
		}
	}

	protected event OnScannerZoom( argZoom : Float )
	{
		if( ( argZoom * 2.0 ) > 2.0 )
		{
			inkTextRef.SetText( m_ZoomNumber, FloatToStringPrec( MaxF( 1.0, argZoom * 2.0 ), 1 ) + "x" );
		}
		else
		{
			inkTextRef.SetText( m_ZoomNumber, FloatToStringPrec( MaxF( 1.0, ( argZoom * 2.0 ) - 1.0 ), 1 ) + "x" );
		}
		inkImageRef.SetMargin( m_ZoomMoveBracketL, inkMargin( 0.0, 0.0, 560.0 - ( argZoom * 60.0 ), 0.0 ) );
		inkImageRef.SetMargin( m_ZoomMoveBracketR, inkMargin( 560.0 - ( argZoom * 60.0 ), 0.0, 0.0, 0.0 ) );
		if( argZoom < argZoomBuffered )
		{
			if( ( !( zoomDownAnim ) || !( zoomDownAnim.IsPlaying() ) ) && ( !( zoomUpAnim ) || !( zoomUpAnim.IsPlaying() ) ) )
			{
				zoomDownAnim = PlayLibraryAnimation( 'zoomDown' );
			}
		}
		if( argZoom > argZoomBuffered )
		{
			if( ( !( zoomDownAnim ) || !( zoomDownAnim.IsPlaying() ) ) && ( !( zoomUpAnim ) || !( zoomUpAnim.IsPlaying() ) ) )
			{
				zoomUpAnim = PlayLibraryAnimation( 'zoomUp' );
			}
		}
		argZoomBuffered = argZoom;
	}

	protected event OnProgressChange( val : Float )
	{
		var barActive : Bool;
		var shouldShowScanner : Bool;
		barActive = ( val > 0.0 ) && ( val < 1.0 );
		shouldShowScanner = ShouldShowScanner();
		if( barActive && shouldShowScanner )
		{
			inkImageRef.SetSize( m_scannerBarFill, Vector2( val * 418.0, 15.0 ) );
			if( !( m_BracketsAppearAnimProxy.IsPlaying() ) && ( val < 0.05 ) )
			{
				m_BracketsAppearAnimProxy = PlayLibraryAnimation( 'BracketsAppearAnim' );
			}
			if( !( m_LockOnAnimProxy.IsPlaying() ) && ( val > 0.94999999 ) )
			{
				m_LockOnAnimProxy = PlayLibraryAnimation( 'BracketsAppearAnim' );
			}
		}
		inkCompoundRef.SetVisible( m_scannerBarWidget, barActive && shouldShowScanner );
	}

	private function ShouldShowScanner() : Bool
	{
		var target : GameObject;
		if( EntityID.IsDefined( m_currentTarget ) )
		{
			target = ( ( GameObject )( GameInstance.FindEntityByID( GetOwner().GetGame(), m_currentTarget ) ) );
			if( target )
			{
				return target.ShouldShowScanner() && !( target.IsScanned() );
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}

	private function GetOwner() : weak< GameObject >
	{
		return ( ( GameObject )( GetOwnerEntity() ) );
	}

	protected event OnProgressBarFluffTextChange( val : String )
	{
		if( !( IsStringValid( val ) ) )
		{
			val = "SCANNING";
		}
		inkTextRef.SetLocalizedTextScript( m_scannerBarFluffText, val );
	}

	protected event OnStateChanged( val : Variant )
	{
		var idleAnimOptions : inkAnimOptions;
		var state : gameScanningState;
		state = ( ( gameScanningState )val );
		m_isFullyScanned = state == gameScanningState.Complete;
		ComputeVisibility();
		if( !( m_IdleAnimProxy.IsPlaying() ) )
		{
			idleAnimOptions.loopInfinite = true;
			m_IdleAnimProxy = PlayLibraryAnimation( 'InfiniteIdleAnimation', idleAnimOptions );
		}
	}

	protected event OnScannedObject( val : EntityID )
	{
		m_currentTargetBuffered = m_currentTarget;
		m_currentTarget = val;
		ComputeVisibility();
	}

	protected event OnScannerObjectStats( val : Variant )
	{
		m_scannerData.questEntries.Clear();
		m_scannerData = ( ( scannerDataStructure )val );
		if( !( m_shouldShowScanner ) )
		{
			return false;
		}
	}

	private function ShouldShowScanner( currentTargetObject : weak< GameObject > ) : Bool
	{
		if( EntityID.IsDefined( m_currentTarget ) )
		{
			return currentTargetObject.ShouldShowScanner();
		}
		return false;
	}

	private function GetHudManager() : HUDManager
	{
		return GetOwner().GetHudManager();
	}

}

