class BraindanceGameController extends inkHUDGameController
{
	private editable var m_currentTimerMarker : inkWidgetRef;
	private editable var m_currentTimerText : inkTextRef;
	private editable var m_activeLayer : inkTextRef;
	private editable var m_layerIcon : inkImageRef;
	private editable var m_layerThermalIcon : inkImageRef;
	private editable var m_layerVisualIcon : inkImageRef;
	private editable var m_layerAudioIcon : inkImageRef;
	private editable var m_cursorPoint : inkWidgetRef;
	private editable var m_buttonHintsManagerRef : inkWidgetRef;
	private const editable var m_clueHolder : array< inkCompoundRef >;
	private const editable var m_clueBarHolder : array< inkWidgetRef >;
	private const editable var m_speedIndicatorManagers : array< inkWidgetRef >;
	private var m_clueArray : array< weak< BraindanceClueLogicController > >;
	private var m_buttonHintsController : weak< ButtonHints >;
	private var m_barSize : Float;
	private var m_braindanceDuration : Float;
	private var m_currentTime : Float;
	private var m_rootWidget : weak< inkWidget >;
	private var m_currentLayer : gameuiEBraindanceLayer;
	private var m_currentSpeed : scnPlaySpeed;
	private var m_currentDirection : scnPlayDirection;
	private var m_startingTimerTopMargin : Float;
	private var m_gameInstance : GameInstance;
	private var m_braindanceBB : weak< IBlackboard >;
	private var m_braindanceDef : BraindanceBlackboardDef;
	private var m_ClueBBID : CallbackHandle;
	private var m_VisionModeBBID : CallbackHandle;
	private var m_ProgressBBID : CallbackHandle;
	private var m_SectionTimeBBID : CallbackHandle;
	private var m_IsActiveBBID : CallbackHandle;
	private var m_EnableExitBBID : CallbackHandle;
	private var m_IsFPPBBID : CallbackHandle;
	private var m_PlaybackSpeedID : CallbackHandle;
	private var m_PlaybackDirectionID : CallbackHandle;
	private var m_isFPPMode : Bool;
	private var m_showTimelineAnimation : inkAnimProxy;
	private var m_hideTimelineAnimation : inkAnimProxy;
	private var m_showWidgetAnimation : inkAnimProxy;

	protected event OnInitialize()
	{
		var timerPositionMargin : inkMargin;
		var barController : BraindanceBarLogicController;
		m_barSize = 2000.0;
		m_braindanceDuration = 100.0;
		m_isFPPMode = true;
		timerPositionMargin = inkWidgetRef.GetMargin( m_currentTimerMarker );
		m_startingTimerTopMargin = timerPositionMargin.top;
		m_buttonHintsController = ( ( ButtonHints )( SpawnFromExternal( inkWidgetRef.Get( m_buttonHintsManagerRef ), R"base\gameplay\gui\common\buttonhints_vertical.inkwidget", 'Root' ).GetController() ) );
		m_rootWidget = GetRootWidget();
		m_rootWidget.SetVisible( false );
		if( m_clueBarHolder.Size() == 3 )
		{
			barController = ( ( BraindanceBarLogicController )( inkWidgetRef.GetController( m_clueBarHolder[ 0 ] ) ) );
			barController.SetBarLayer( gameuiEBraindanceLayer.Visual, GetStateName( gameuiEBraindanceLayer.Visual ) );
			barController = ( ( BraindanceBarLogicController )( inkWidgetRef.GetController( m_clueBarHolder[ 1 ] ) ) );
			barController.SetBarLayer( gameuiEBraindanceLayer.Thermal, GetStateName( gameuiEBraindanceLayer.Thermal ) );
			barController = ( ( BraindanceBarLogicController )( inkWidgetRef.GetController( m_clueBarHolder[ 2 ] ) ) );
			barController.SetBarLayer( gameuiEBraindanceLayer.Audio, GetStateName( gameuiEBraindanceLayer.Audio ) );
		}
		SetupBB();
		SetBraindanceBaseInput();
	}

	protected event OnUnInitialize()
	{
		UnregisterFromBB();
	}

	private function SetupBB()
	{
		var bdSystem : BraindanceSystem;
		var bdEvent : BraindanceInputChangeEvent;
		m_braindanceDef = GetAllBlackboardDefs().Braindance;
		m_braindanceBB = GetBlackboardSystem().Get( m_braindanceDef );
		if( m_braindanceBB )
		{
			m_ClueBBID = m_braindanceBB.RegisterDelayedListenerVariant( m_braindanceDef.Clue, this, 'OnClueDataUpdated' );
			m_VisionModeBBID = m_braindanceBB.RegisterDelayedListenerInt( m_braindanceDef.activeBraindanceVisionMode, this, 'OnVisionModeUpdated' );
			m_ProgressBBID = m_braindanceBB.RegisterDelayedListenerFloat( m_braindanceDef.Progress, this, 'OnProgressUpdated' );
			m_SectionTimeBBID = m_braindanceBB.RegisterDelayedListenerFloat( m_braindanceDef.SectionTime, this, 'OnSectionTimeUpdated' );
			m_IsActiveBBID = m_braindanceBB.RegisterDelayedListenerBool( m_braindanceDef.IsActive, this, 'OnIsActiveUpdated' );
			m_EnableExitBBID = m_braindanceBB.RegisterDelayedListenerBool( m_braindanceDef.EnableExit, this, 'OnExitEnabled' );
			m_IsFPPBBID = m_braindanceBB.RegisterDelayedListenerBool( m_braindanceDef.IsFPP, this, 'OnIsFPPUpdated' );
			m_PlaybackSpeedID = m_braindanceBB.RegisterDelayedListenerVariant( m_braindanceDef.PlaybackSpeed, this, 'OnPlaybackSpeedUpdated' );
			m_PlaybackDirectionID = m_braindanceBB.RegisterDelayedListenerVariant( m_braindanceDef.PlaybackDirection, this, 'OnPlaybackDirectionUpdated' );
			if( m_braindanceBB.GetBool( m_braindanceDef.IsActive ) )
			{
				OnIsActiveUpdated( true );
				OnSectionTimeUpdated( m_braindanceBB.GetFloat( m_braindanceDef.SectionTime ) );
				OnIsFPPUpdated( m_braindanceBB.GetBool( m_braindanceDef.IsFPP ) );
				OnVisionModeUpdated( m_braindanceBB.GetInt( m_braindanceDef.activeBraindanceVisionMode ) );
				bdSystem = ( ( BraindanceSystem )( GameInstance.GetScriptableSystemsContainer( GetPlayerControlledObject().GetGame() ).Get( 'BraindanceSystem' ) ) );
				bdEvent = new BraindanceInputChangeEvent;
				bdEvent.bdSystem = bdSystem;
				GameInstance.GetUISystem( GetPlayerControlledObject().GetGame() ).QueueEvent( bdEvent );
				m_gameInstance = GetPlayerControlledObject().GetGame();
			}
		}
	}

	private function UnregisterFromBB()
	{
		if( m_braindanceBB )
		{
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.Clue, m_ClueBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.activeBraindanceVisionMode, m_VisionModeBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.Progress, m_ProgressBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.SectionTime, m_SectionTimeBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.IsActive, m_IsActiveBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.EnableExit, m_EnableExitBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.IsFPP, m_IsFPPBBID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.PlaybackSpeed, m_PlaybackSpeedID );
			m_braindanceBB.UnregisterDelayedListener( m_braindanceDef.PlaybackDirection, m_PlaybackDirectionID );
		}
		m_braindanceBB = NULL;
	}

	protected event OnBraindanceInputChangeEvent( evt : BraindanceInputChangeEvent )
	{
		var inputMask : SBraindanceInputMask;
		inputMask = evt.bdSystem.GetInputMask();
		m_buttonHintsController.ClearButtonHints();
		if( inputMask.pauseAction )
		{
			m_buttonHintsController.AddButtonHint( 'Pause', 'UI-ScriptExports-Play/Pause0' );
		}
		if( inputMask.playForwardAction )
		{
			m_buttonHintsController.AddButtonHint( 'PlayForward', 'UI-ScriptExports-FastForward0', true );
		}
		if( inputMask.playBackwardAction )
		{
			m_buttonHintsController.AddButtonHint( 'PlayBackward', 'UI-ScriptExports-Rewind0', true );
		}
		if( inputMask.restartAction )
		{
			m_buttonHintsController.AddButtonHint( 'Restart', 'UI-ScriptExports-Restart0', true );
		}
		if( inputMask.switchLayerAction && !( m_isFPPMode ) )
		{
			m_buttonHintsController.AddButtonHint( 'SwitchLayer', 'UI-ScriptExports-SwitchLayer0' );
		}
		if( inputMask.cameraToggleAction )
		{
			m_buttonHintsController.AddButtonHint( 'BdCameraToggle', GetLeftShoulderLocKey() );
		}
		OnExitEnabled( m_braindanceBB.GetBool( m_braindanceDef.EnableExit ) );
	}

	protected event OnClueDataUpdated( value : Variant )
	{
		var clueDescriptor : gameuiBraindanceClueDescriptor;
		var clueData : BraindanceClueData;
		var clueIndex : Int32;
		var duplicatedClue : Bool;
		clueDescriptor = ( ( gameuiBraindanceClueDescriptor )value );
		clueData.startTime = clueDescriptor.startTime;
		clueData.duration = clueDescriptor.endTime - clueDescriptor.startTime;
		switch( clueDescriptor.mode )
		{
			case gameuiEClueDescriptorMode.Add:
				clueData.state = ClueState.active;
			break;
			case gameuiEClueDescriptorMode.Finish:
				clueData.state = ClueState.complete;
			break;
		}
		clueData.layer = clueDescriptor.layer;
		clueData.id = clueDescriptor.clueName;
		for( clueIndex = 0; !( duplicatedClue ) && ( clueIndex < m_clueArray.Size() ); clueIndex += 1 )
		{
			if( m_clueArray[ clueIndex ].GetBraindanceClueId() == clueData.id )
			{
				duplicatedClue = true;
				break;
			}
		}
		if( !( duplicatedClue ) )
		{
			AddClue( clueData );
			clueIndex = clueIndex + 1;
		}
		UpdateClues();
		if( clueData.state == ClueState.complete )
		{
			m_clueArray[ clueIndex ].HideClue();
		}
	}

	protected event OnProgressUpdated( value : Float )
	{
		m_currentTime = value;
		SetBraindanceProgress();
		UpdateClues();
	}

	protected event OnSectionTimeUpdated( value : Float )
	{
		m_braindanceDuration = value;
	}

	protected event OnIsActiveUpdated( value : Bool )
	{
		if( !( value ) )
		{
			m_isFPPMode = true;
			SetBraindanceBaseInput();
			m_buttonHintsController.RemoveButtonHint( 'SwitchLayer' );
		}
		else
		{
			m_buttonHintsController.AddButtonHint( 'SwitchLayer', 'UI-ScriptExports-SwitchLayer0' );
		}
		UpdateBraindance( value );
	}

	protected event OnIsFPPUpdated( value : Bool )
	{
		var inputMask : SBraindanceInputMask;
		var bdSystem : BraindanceSystem;
		bdSystem = ( ( BraindanceSystem )( GameInstance.GetScriptableSystemsContainer( GetPlayerControlledObject().GetGame() ).Get( 'BraindanceSystem' ) ) );
		inputMask = bdSystem.GetInputMask();
		m_isFPPMode = value;
		m_buttonHintsController.AddButtonHint( 'BdCameraToggle', GetLeftShoulderLocKey() );
		if( inputMask.switchLayerAction && !( m_isFPPMode ) )
		{
			m_buttonHintsController.AddButtonHint( 'SwitchLayer', 'UI-ScriptExports-SwitchLayer0' );
		}
		else
		{
			m_buttonHintsController.RemoveButtonHint( 'SwitchLayer' );
		}
	}

	protected event OnPlaybackSpeedUpdated( value : Variant )
	{
		m_currentSpeed = ( ( scnPlaySpeed )value );
		UpdateSpeedIndicators();
	}

	protected event OnPlaybackDirectionUpdated( value : Variant )
	{
		m_currentDirection = ( ( scnPlayDirection )value );
		UpdateSpeedIndicators();
	}

	private function UpdateSpeedIndicators()
	{
		var i : Int32;
		var speedIndicator : SpeedIndicatorIconsManager;
		for( i = 0; i < m_speedIndicatorManagers.Size(); i += 1 )
		{
			speedIndicator = ( ( SpeedIndicatorIconsManager )( inkWidgetRef.GetController( m_speedIndicatorManagers[ i ] ) ) );
			speedIndicator.SetBraindanceSpeed( m_currentSpeed, m_currentDirection );
		}
	}

	protected event OnVisionModeUpdated( value : Int32 )
	{
		SetVisionMode( ( ( gameuiEBraindanceLayer )( value ) ) );
		UpdateClues();
	}

	protected event OnExitEnabled( value : Bool )
	{
		if( value )
		{
			m_buttonHintsController.AddButtonHint( 'ExitBraindance', 'UI-ScriptExports-Close' );
		}
		else
		{
			m_buttonHintsController.RemoveButtonHint( 'ExitBraindance' );
		}
	}

	public function UpdateBraindance( active : Bool )
	{
		var i : Int32;
		if( active )
		{
			Intro();
			for( i = 0; i < m_clueHolder.Size(); i += 1 )
			{
				inkCompoundRef.RemoveAllChildren( m_clueHolder[ i ] );
			}
			m_clueArray.Clear();
		}
		else
		{
			Outro();
		}
	}

	private function SetBraindanceBaseInput()
	{
		m_buttonHintsController.ClearButtonHints();
		m_buttonHintsController.AddButtonHint( 'Pause', 'UI-ScriptExports-Play/Pause0' );
		m_buttonHintsController.AddButtonHint( 'PlayForward', 'UI-ScriptExports-FastForward0', true );
		m_buttonHintsController.AddButtonHint( 'PlayBackward', 'UI-ScriptExports-Rewind0', true );
		m_buttonHintsController.AddButtonHint( 'Restart', 'UI-ScriptExports-Restart0', true );
		m_buttonHintsController.AddButtonHint( 'BdCameraToggle', GetLeftShoulderLocKey() );
		OnExitEnabled( m_braindanceBB.GetBool( m_braindanceDef.EnableExit ) );
	}

	public function SetBraindanceProgress()
	{
		var currentPercent : Float;
		var currentPosition : Float;
		var newPositionMargin : inkMargin;
		currentPercent = m_currentTime;
		currentPosition = currentPercent * m_barSize;
		newPositionMargin.left = currentPosition;
		inkWidgetRef.SetMargin( m_currentTimerMarker, newPositionMargin );
		inkTextRef.SetText( m_currentTimerText, GetTimeMS( m_braindanceDuration * currentPercent ) );
	}

	public function AddClue( clueData : BraindanceClueData )
	{
		var widget : inkWidget;
		var controller : weak< BraindanceClueLogicController >;
		var clueSize, cluePosition, cluePercentage, clueStartPercentage : Float;
		var clueMargin : inkMargin;
		var holder : inkCompoundRef;
		var initialSize : Vector2;
		switch( clueData.layer )
		{
			case gameuiEBraindanceLayer.Visual:
				holder = m_clueHolder[ 0 ];
			break;
			case gameuiEBraindanceLayer.Thermal:
				holder = m_clueHolder[ 1 ];
			break;
			case gameuiEBraindanceLayer.Audio:
				holder = m_clueHolder[ 2 ];
			break;
			default:
				return;
		}
		widget = ( ( inkCanvas )( SpawnFromLocal( inkCompoundRef.Get( holder ), 'Clue' ) ) );
		controller = ( ( BraindanceClueLogicController )( widget.GetController() ) );
		cluePercentage = clueData.duration / m_braindanceDuration;
		clueSize = cluePercentage * m_barSize;
		controller.SetupData( clueSize, clueData );
		clueStartPercentage = clueData.startTime / m_braindanceDuration;
		cluePosition = ( clueStartPercentage * m_barSize ) - 12.0;
		clueMargin.left = cluePosition;
		widget.SetMargin( clueMargin );
		widget.SetState( GetStateName( clueData.layer ) );
		widget.SetAnchorPoint( 0.0, 0.5 );
		widget.SetAnchor( inkEAnchor.CenterLeft );
		widget.SetVAlign( inkEVerticalAlign.Center );
		initialSize = widget.GetSize();
		initialSize.Y = 30.0;
		widget.SetSize( initialSize );
		if( clueData.duration <= 0.01 )
		{
			widget.SetVisible( false );
		}
		m_clueArray.PushBack( controller );
	}

	private function SetVisionMode( layer : gameuiEBraindanceLayer )
	{
		var localizedLayerName : String;
		var layerIconName : CName;
		var layerStateName : CName;
		var i : Int32;
		var cursorPointMargin : inkMargin;
		var barController : BraindanceBarLogicController;
		var clueBarOpacity : Float;
		var clueBarScaleY : Float;
		clueBarOpacity = 0.69999999;
		clueBarScaleY = 0.5;
		m_currentLayer = layer;
		switch( m_currentLayer )
		{
			case gameuiEBraindanceLayer.Visual:
				localizedLayerName = "LocKey#22109";
			layerIconName = 'braindance_visual_icon';
			cursorPointMargin.top = -45.0;
			inkCompoundRef.SetOpacity( m_clueHolder[ 0 ], 1.0 );
			inkCompoundRef.SetScale( m_clueHolder[ 0 ], Vector2( 1.0, 1.0 ) );
			inkCompoundRef.SetOpacity( m_clueHolder[ 1 ], clueBarOpacity );
			inkCompoundRef.SetScale( m_clueHolder[ 1 ], Vector2( 1.0, clueBarScaleY ) );
			inkCompoundRef.SetOpacity( m_clueHolder[ 2 ], clueBarOpacity );
			inkCompoundRef.SetScale( m_clueHolder[ 2 ], Vector2( 1.0, clueBarScaleY ) );
			break;
			case gameuiEBraindanceLayer.Thermal:
				localizedLayerName = "UI-ResourceExports-BraindanceThermalLayerName";
			layerIconName = 'braindance_thermal_icon';
			cursorPointMargin.top = -10.0;
			inkCompoundRef.SetOpacity( m_clueHolder[ 0 ], clueBarOpacity );
			inkCompoundRef.SetOpacity( m_clueHolder[ 1 ], 1.0 );
			inkCompoundRef.SetOpacity( m_clueHolder[ 2 ], clueBarOpacity );
			inkCompoundRef.SetScale( m_clueHolder[ 0 ], Vector2( 1.0, clueBarScaleY ) );
			inkCompoundRef.SetScale( m_clueHolder[ 1 ], Vector2( 1.0, 1.0 ) );
			inkCompoundRef.SetScale( m_clueHolder[ 2 ], Vector2( 1.0, clueBarScaleY ) );
			break;
			case gameuiEBraindanceLayer.Audio:
				localizedLayerName = "LocKey#23590";
			layerIconName = 'braindance_sound_icon';
			cursorPointMargin.top = 25.0;
			inkCompoundRef.SetOpacity( m_clueHolder[ 0 ], clueBarOpacity );
			inkCompoundRef.SetOpacity( m_clueHolder[ 1 ], clueBarOpacity );
			inkCompoundRef.SetOpacity( m_clueHolder[ 2 ], 1.0 );
			inkCompoundRef.SetScale( m_clueHolder[ 0 ], Vector2( 1.0, clueBarScaleY ) );
			inkCompoundRef.SetScale( m_clueHolder[ 1 ], Vector2( 1.0, clueBarScaleY ) );
			inkCompoundRef.SetScale( m_clueHolder[ 2 ], Vector2( 1.0, 1.0 ) );
			break;
		}
		localizedLayerName = GetLocalizedText( localizedLayerName );
		inkTextRef.SetLetterCase( m_activeLayer, textLetterCase.UpperCase );
		inkTextRef.SetText( m_activeLayer, localizedLayerName );
		inkImageRef.SetTexturePart( m_layerIcon, layerIconName );
		layerStateName = GetStateName( m_currentLayer );
		inkImageRef.SetState( m_layerIcon, layerStateName );
		inkImageRef.SetState( m_layerThermalIcon, layerStateName );
		inkImageRef.SetState( m_layerVisualIcon, layerStateName );
		inkImageRef.SetState( m_layerAudioIcon, layerStateName );
		inkTextRef.SetState( m_activeLayer, layerStateName );
		inkWidgetRef.SetState( m_currentTimerMarker, layerStateName );
		inkWidgetRef.SetMargin( m_cursorPoint, cursorPointMargin );
		for( i = 0; i < m_clueBarHolder.Size(); i += 1 )
		{
			barController = ( ( BraindanceBarLogicController )( inkWidgetRef.GetController( m_clueBarHolder[ i ] ) ) );
			barController.UpdateActiveLayer( m_currentLayer );
		}
	}

	private function UpdateClues()
	{
		var i : Int32;
		var controller : weak< BraindanceClueLogicController >;
		for( i = 0; i < m_clueArray.Size(); i += 1 )
		{
			controller = m_clueArray[ i ];
			controller.UpdateLayer( m_currentLayer );
			controller.UpdateTimeWindow( m_currentTime * m_braindanceDuration );
		}
	}

	private function GetStateName( stateEnum : gameuiEBraindanceLayer ) : CName
	{
		switch( stateEnum )
		{
			case gameuiEBraindanceLayer.Visual:
				return 'Visual';
			case gameuiEBraindanceLayer.Audio:
				return 'Audio';
			case gameuiEBraindanceLayer.Thermal:
				return 'Thermal';
		}
		return 'Default';
	}

	private function GetLeftShoulderLocKey() : CName
	{
		return ( ( m_isFPPMode ) ? ( 'UI-ScriptExports-EditorMode' ) : ( 'UI-ScriptExports-PlaybackMode' ) );
	}

	private function ShowInputHint( action : CName, label : CName )
	{
		var evt : UpdateInputHintEvent;
		var data : InputHintData;
		data.action = action;
		data.source = 'Braindance';
		data.localizedLabel = GetLocalizedTextByKey( label );
		evt = new UpdateInputHintEvent;
		evt.data = data;
		evt.show = true;
		evt.targetHintContainer = 'GameplayInputHelper';
		GameInstance.GetUISystem( m_gameInstance ).QueueEvent( evt );
	}

	private function HideInputHint( action : CName )
	{
		var evt : UpdateInputHintEvent;
		var data : InputHintData;
		data.action = action;
		data.source = 'Braindance';
		evt = new UpdateInputHintEvent;
		evt.data = data;
		evt.show = false;
		evt.targetHintContainer = 'GameplayInputHelper';
		GameInstance.GetUISystem( m_gameInstance ).QueueEvent( evt );
	}

	private function Intro()
	{
		m_rootWidget.SetVisible( true );
		m_showWidgetAnimation = PlayLibraryAnimation( 'SHOW' );
	}

	private function Outro()
	{
		Hide();
	}

	public function Hide()
	{
		m_rootWidget.SetVisible( false );
	}

	private function GetTimeMS( seconds : Float ) : String
	{
		var secondsLeft : Int32;
		var minutesLeft : Int32;
		var secondsString : String;
		var minutesString : String;
		minutesLeft = ( ( Int32 )( seconds ) ) / 60;
		minutesString = ( ( minutesLeft >= 10 ) ? ( "" ) : ( "0" ) );
		minutesString += ( ( String )( minutesLeft ) );
		secondsLeft = ( ( Int32 )( seconds ) ) % 60;
		secondsString = ( ( secondsLeft >= 10 ) ? ( "" ) : ( "0" ) );
		secondsString += ( ( String )( secondsLeft ) );
		return ( minutesString + ":" ) + secondsString;
	}

}

class BraindanceClueLogicController extends inkLogicController
{
	private editable var bg : inkWidgetRef;
	private editable var m_timelineActiveAnimationName : CName;
	private editable var m_timelineDisabledAnimationName : CName;
	private var m_timelineActiveAnimation : inkAnimProxy;
	private var m_timelineDisabledAnimation : inkAnimProxy;
	private var m_state : ClueState;
	private var m_data : BraindanceClueData;
	private var m_isInLayer : Bool;
	private var m_isInTimeWindow : Bool;

	protected event OnInitialize() {}

	public function SetupData( width : Float, data : BraindanceClueData )
	{
		var newSize : Vector2;
		var currentSize : Vector2;
		m_data = data;
		currentSize = inkWidgetRef.GetSize( bg );
		newSize.X = width;
		newSize.Y = currentSize.Y;
		inkWidgetRef.SetSize( bg, newSize );
		GetRootWidget().SetSize( newSize );
	}

	public function UpdateLayer( layer : gameuiEBraindanceLayer )
	{
		m_isInLayer = m_data.layer == layer;
		UpdateOpacity();
	}

	public function UpdateTimeWindow( currentTime : Float )
	{
		m_isInTimeWindow = ( m_data.startTime <= currentTime ) && ( currentTime <= ( m_data.startTime + m_data.duration ) );
		UpdateOpacity();
	}

	private function UpdateOpacity()
	{
		var totalOpacity : Float;
		totalOpacity = 0.60000002;
		if( m_isInLayer )
		{
			totalOpacity = 0.69999999;
			if( m_isInTimeWindow )
			{
				totalOpacity = 1.0;
			}
		}
		GetRootWidget().SetOpacity( totalOpacity );
	}

	public function HideClue()
	{
		if( GetRootWidget().IsVisible() )
		{
			GetRootWidget().SetVisible( false );
		}
	}

	public function GetBraindanceClueId() : CName
	{
		return m_data.id;
	}

	public function GetBraindanceClueState() : ClueState
	{
		return m_data.state;
	}

}

class SpeedIndicatorIconsManager extends inkLogicController
{
	private editable var m_speedIndicator : inkImageRef;
	private editable var m_mirroredSpeedIndicator : inkImageRef;

	public function SetBraindanceSpeed( currentSpeed : scnPlaySpeed, currentDirection : scnPlayDirection )
	{
		var speed : Int32;
		var newIconPart : CName;
		var translationSign : Int32;
		var translationIntensity : Float;
		var selectedInkWidget : inkImageRef;
		var hiddenInkWidget : inkImageRef;
		speed = ( ( Int32 )( currentSpeed ) );
		if( currentSpeed == scnPlaySpeed.Pause )
		{
			newIconPart = 'pause';
			selectedInkWidget = m_speedIndicator;
			hiddenInkWidget = m_mirroredSpeedIndicator;
			translationSign = 1;
			translationIntensity = 0.0;
		}
		else
		{
			if( currentDirection != scnPlayDirection.Forward )
			{
				selectedInkWidget = m_speedIndicator;
				hiddenInkWidget = m_mirroredSpeedIndicator;
				translationSign = -1;
			}
			else
			{
				selectedInkWidget = m_mirroredSpeedIndicator;
				hiddenInkWidget = m_speedIndicator;
				translationSign = 1;
			}
			switch( speed )
			{
				case 1:
					newIconPart = 'speed_1';
				translationIntensity = 0.0;
				break;
				case 2:
					newIconPart = 'speed_2';
				translationIntensity = 15.0;
				break;
				case 3:
					newIconPart = 'speed_3';
				translationIntensity = 30.0;
				break;
			}
		}
		inkImageRef.SetTexturePart( selectedInkWidget, newIconPart );
		inkImageRef.SetTranslation( selectedInkWidget, ( ( Float )( translationSign ) ) * translationIntensity, 0.0 );
		inkImageRef.SetVisible( selectedInkWidget, true );
		inkImageRef.SetVisible( hiddenInkWidget, false );
	}

}

class BraindanceBarLogicController extends inkLogicController
{
	private var m_layer : gameuiEBraindanceLayer;
	private var m_isInLayer : Bool;
	private editable var m_timelineActiveAnimationName : CName;
	private editable var m_timelineDisabledAnimationName : CName;
	private var m_timelineActiveAnimation : inkAnimProxy;
	private var m_timelineDisabledAnimation : inkAnimProxy;

	public function SetBarLayer( layer : gameuiEBraindanceLayer, stateLayerName : CName )
	{
		m_layer = layer;
		GetRootWidget().SetState( stateLayerName );
	}

	public function UpdateActiveLayer( layer : gameuiEBraindanceLayer )
	{
		m_isInLayer = m_layer == layer;
		UpdateOpacity();
	}

	private function UpdateOpacity()
	{
		var totalOpacity : Float;
		totalOpacity = 0.30000001;
		if( m_isInLayer )
		{
			totalOpacity = 0.64999998;
			m_timelineActiveAnimation = PlayLibraryAnimation( m_timelineActiveAnimationName );
		}
		else
		{
			m_timelineDisabledAnimation = PlayLibraryAnimation( m_timelineDisabledAnimationName );
		}
		GetRootWidget().SetOpacity( totalOpacity );
	}

}

enum ClueState
{
	active = 0,
	complete = 1,
}

struct BraindanceClueData
{
	var id : CName;
	var startTime : Float;
	var duration : Float;
	var state : ClueState;
	var layer : gameuiEBraindanceLayer;
}

