class dialogWidgetGameController extends InteractionUIBase
{
	private var m_root : weak< inkCanvas >;
	private editable var m_hubsContainer : inkBasePanelRef;
	private var m_hubControllers : array< weak< DialogHubLogicController > >;
	private var m_activeHubController : weak< DialogHubLogicController >;
	private var m_data : DialogChoiceHubs;
	private var m_activeHubID : Int32;
	default m_activeHubID = -1;
	private var m_prevActiveHubID : Int32;
	private var m_selectedIndex : Int32;
	default m_selectedIndex = 0;
	private var m_fadeAnimTime : Float;
	default m_fadeAnimTime = 0.5;
	private var m_fadeDelay : Float;
	default m_fadeDelay = 1.0;
	private var m_dialogFocusInputHintShown : Bool;
	private var m_hubAvailable : Bool;
	private var m_animCloseHudProxy : inkAnimProxy;
	var currentFadeItem : weak< DialogHubLogicController >;
	private var blackboard : weak< IBlackboard >;
	private var uiSystemBB : UI_SystemDef;
	private var uiSystemId : CallbackHandle;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_root = ( ( inkCanvas )( GetRootWidget() ) );
		blackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_System );
		uiSystemBB = GetAllBlackboardDefs().UI_System;
		uiSystemId = blackboard.RegisterListenerBool( uiSystemBB.IsInMenu, this, 'OnMenuVisibilityChange' );
	}

	protected event OnUninitialize()
	{
		if( uiSystemId )
		{
			blackboard.UnregisterListenerBool( uiSystemBB.IsInMenu, uiSystemId );
		}
		super.OnUninitialize();
	}

	protected override function UpdateDialogsData( const data : ref< DialogChoiceHubs > )
	{
		m_data = data;
	}

	protected event OnDialogsActivateHub( activeHubId : Int32 )
	{
		if( m_activeHubID != activeHubId )
		{
			m_prevActiveHubID = m_activeHubID;
			m_activeHubID = activeHubId;
		}
		super.OnDialogsActivateHub( activeHubId );
	}

	protected event OnDialogsSelectIndex( index : Int32 )
	{
		m_selectedIndex = index;
		super.OnDialogsSelectIndex( index );
	}

	protected override function OnInteractionsChanged()
	{
		var hubsListData : array< ListChoiceHubData >;
		var hubData : ListChoiceHubData;
		var currentItem : weak< DialogHubLogicController >;
		var i, count, totalCountAcrossHubs, currentInd : Int32;
		var hasAboveElements, hasBelowElements : Bool;
		hubsListData = m_data.choiceHubs;
		count = hubsListData.Size();
		AdjustHubsCount( count );
		totalCountAcrossHubs = 0;
		for( i = 0; i < count; i += 1 )
		{
			totalCountAcrossHubs += hubsListData[ i ].choices.Size();
		}
		m_hubAvailable = false;
		currentInd = 0;
		for( i = 0; i < count; i += 1 )
		{
			currentItem = m_hubControllers[ i ];
			hubData = hubsListData[ i ];
			hasAboveElements = ( ( i != 0 ) || m_AreInteractionsOpen ) || m_IsLootingOpen;
			hasBelowElements = ( i != ( count - 1 ) ) || m_AreContactsOpen;
			currentItem.SetData( hubData, hubData.id == m_activeHubID, m_selectedIndex, hasAboveElements, hasBelowElements, currentInd, totalCountAcrossHubs );
			currentInd += hubData.choices.Size();
			if( !( m_hubAvailable ) )
			{
				m_hubAvailable = true;
			}
		}
		if( count > 0 )
		{
			m_hubControllers[ 0 ].OverrideInputButton( m_activeHubID == -1 );
		}
		if( m_root )
		{
			m_root.SetVisible( m_AreDialogsOpen );
		}
	}

	private function AdjustHubsCount( count : Int32 )
	{
		var currentItem : weak< DialogHubLogicController >;
		while( m_hubControllers.Size() > count )
		{
			currentItem = m_hubControllers.PopBack();
			inkBasePanelRef.RemoveChild( m_hubsContainer, currentItem.GetRootWidget() );
		}
		while( m_hubControllers.Size() < count )
		{
			currentItem = ( ( DialogHubLogicController )( SpawnFromLocal( inkBasePanelRef.Get( m_hubsContainer ), 'hub' ).GetController() ) );
			m_hubControllers.PushBack( currentItem );
		}
	}

	private function CloseDelayed( hudController : weak< DialogHubLogicController > )
	{
		var opacityInterp : inkAnimTransparency;
		var animDef : inkAnimDef;
		currentFadeItem = hudController;
		if( m_animCloseHudProxy.IsPlaying() )
		{
			return;
		}
		if( m_animCloseHudProxy.IsPlaying() )
		{
			m_animCloseHudProxy.Stop();
		}
		animDef = new inkAnimDef;
		opacityInterp = new inkAnimTransparency;
		opacityInterp.SetStartDelay( m_fadeDelay );
		opacityInterp.SetStartTransparency( 1.0 );
		opacityInterp.SetEndTransparency( 0.0 );
		opacityInterp.SetDuration( m_fadeAnimTime );
		animDef.AddInterpolator( opacityInterp );
		m_animCloseHudProxy = hudController.GetRootWidget().PlayAnimation( animDef );
		m_animCloseHudProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnFinish' );
		hudController.FadeOutItems( m_fadeAnimTime );
	}

	protected event OnFinish( proxy : inkAnimProxy )
	{
		m_animCloseHudProxy.UnregisterFromCallback( inkanimEventType.OnFinish, this, 'OnFinish' );
		inkBasePanelRef.RemoveChild( m_hubsContainer, currentFadeItem.GetRootWidget() );
		m_animCloseHudProxy.Stop();
	}

	protected event OnMenuVisibilityChange( isMenuVisible : Bool )
	{
		var i, count : Int32;
		var controller : DialogHubLogicController;
		var hubsListData : array< ListChoiceHubData >;
		hubsListData = m_data.choiceHubs;
		count = hubsListData.Size();
		for( i = 0; i < count; i += 1 )
		{
			controller = ( ( DialogHubLogicController )( m_hubControllers[ i ] ) );
			if( controller )
			{
				controller.OnMenuVisibilityChange( isMenuVisible );
			}
		}
	}

}

struct DialogHubData
{
	var m_isSelected : Bool;
	var m_selectedInd : Int32;
	var m_hasAboveElements : Bool;
	var m_hasBelowElements : Bool;
	var m_currentNum : Int32;
	var m_argTotalCountAcrossHubs : Int32;
}

class DialogHubLogicController extends inkLogicController
{
	editable var m_progressBarHolder : inkWidgetRef;
	editable var m_selectionSizeProviderRef : inkWidgetRef;
	editable var m_selectionRoot : inkWidgetRef;
	editable var m_moveAnimTime : Float;
	default m_moveAnimTime = 0.09f;
	private var m_rootWidget : weak< inkWidget >;
	private var m_possessedDialogFluff : weak< inkWidget >;
	private var m_titleWidget : weak< inkText >;
	private var m_titleBorder : weak< inkWidget >;
	private var m_titleContainer : weak< inkCompoundWidget >;
	private var m_mainVert : weak< inkCompoundWidget >;
	private var m_id : Int32;
	private var m_isSelected : Bool;
	default m_isSelected = false;
	private var m_data : ListChoiceHubData;
	private var m_itemControllers : array< weak< DialogChoiceLogicController > >;
	private var m_progressBar : weak< DialogChoiceTimerController >;
	private var m_hasProgressBar : Bool;
	default m_hasProgressBar = false;
	private var m_wasTimmed : Bool;
	default m_wasTimmed = false;
	private var m_isClosingDelayed : Bool;
	private var m_lastSelectedIdx : Int32;
	private var m_inActiveTransparency : Float;
	default m_inActiveTransparency = 0.1;
	private var m_animSelectMarginProxy : inkAnimProxy;
	private var m_animSelectSizeProxy : inkAnimProxy;
	private var m_animSelectMargin : inkAnimDef;
	private var m_animSelectSize : inkAnimDef;
	private var m_animfFadingOutProxy : inkAnimProxy;
	var selectBgSizeInterp : inkAnimSize;
	var selectBgMarginInterp : inkAnimMargin;
	private var m_dialogHubData : DialogHubData;
	private var m_pendingRequests : Int32;
	private var m_spawnTokens : array< weak< inkAsyncSpawnRequest > >;

	protected event OnInitialize()
	{
		m_rootWidget = GetRootWidget();
		m_titleWidget = ( ( inkText )( GetWidget( 'dpadFlex\titleFlex\mainTitle' ) ) );
		m_possessedDialogFluff = ( ( inkWidget )( GetWidget( 'dpadFlex\titleFlex\possessedDialogBorder' ) ) );
		m_titleBorder = ( ( inkWidget )( GetWidget( 'dpadFlex\titleFlex\mainTitleBorder' ) ) );
		m_mainVert = ( ( inkCompoundWidget )( GetWidget( 'mainVerticalContainer' ) ) );
		m_titleContainer = ( ( inkCompoundWidget )( GetWidget( 'dpadFlex\titleFlex' ) ) );
		m_rootWidget.SetOpacity( 1.0 );
	}

	public function OnMenuVisibilityChange( isMenuVisible : Bool )
	{
		if( m_progressBar )
		{
			m_progressBar.OnMenuVisibilityChange( isMenuVisible );
		}
	}

	public function SetData( const value : ref< ListChoiceHubData >, isSelected : Bool, selectedInd : Int32, hasAboveElements : Bool, hasBelowElements : Bool, currentNum : Int32, argTotalCountAcrossHubs : Int32 )
	{
		var count : Int32;
		var currentItem : weak< DialogChoiceLogicController >;
		var curSpawnRequest : weak< inkAsyncSpawnRequest >;
		m_data = value;
		m_id = m_data.id;
		count = m_data.choices.Size();
		m_dialogHubData.m_isSelected = isSelected;
		m_dialogHubData.m_selectedInd = selectedInd;
		m_dialogHubData.m_hasAboveElements = hasAboveElements;
		m_dialogHubData.m_hasBelowElements = hasBelowElements;
		m_dialogHubData.m_currentNum = currentNum;
		m_dialogHubData.m_argTotalCountAcrossHubs = argTotalCountAcrossHubs;
		if( m_isClosingDelayed )
		{
			return;
		}
		while( ( m_pendingRequests > 0 ) && ( ( m_itemControllers.Size() + m_pendingRequests ) > count ) )
		{
			curSpawnRequest = m_spawnTokens.PopBack();
			if( curSpawnRequest )
			{
				curSpawnRequest.Cancel();
				m_pendingRequests -= 1;
			}
		}
		while( m_itemControllers.Size() > count )
		{
			currentItem = m_itemControllers.PopBack();
			m_mainVert.RemoveChild( currentItem.GetRootWidget() );
		}
		while( ( m_itemControllers.Size() + m_pendingRequests ) < count )
		{
			curSpawnRequest = AsyncSpawnFromLocal( m_mainVert, 'item', this, 'OnItemSpawned' );
			m_spawnTokens.PushBack( curSpawnRequest );
			m_pendingRequests += 1;
		}
		if( m_pendingRequests <= 0 )
		{
			UpdateDialogHubData();
		}
	}

	protected event OnItemSpawned( newItem : inkWidget, userData : IScriptable )
	{
		var currentItem : weak< DialogChoiceLogicController >;
		currentItem = ( ( DialogChoiceLogicController )( newItem.GetController() ) );
		m_itemControllers.PushBack( currentItem );
		m_pendingRequests -= 1;
		if( m_pendingRequests <= 0 )
		{
			UpdateDialogHubData();
			m_spawnTokens.Clear();
		}
	}

	private function UpdateDialogHubData()
	{
		var currListChoiceData : ListChoiceData;
		var currentItem : weak< DialogChoiceLogicController >;
		var i, count : Int32;
		var timedProgress, timedDuration : Float;
		var isPossessed : Bool;
		var isTimed : Bool;
		var tags : String;
		var localizedText : String;
		isPossessed = false;
		isTimed = false;
		count = m_data.choices.Size();
		for( i = 0; i < count; i += 1 )
		{
			currentItem = m_itemControllers[ i ];
			currListChoiceData = ( ( ListChoiceData )( m_data.choices[ i ] ) );
			tags = GetCaptionTagsFromArray( currListChoiceData.captionParts.parts );
			localizedText = currListChoiceData.localizedName;
			if( tags == "" && StrBeginsWith( localizedText, "[" ) )
			{
				if( StrSplitFirst( localizedText, "]", tags, localizedText ) )
				{
					tags = StrFrontToUpper( StrAfterFirst( tags, "[" ) );
					if( StrBeginsWith( localizedText, " " ) )
					{
						localizedText = StrAfterFirst( localizedText, " " );
					}
				}
			}
			currentItem.SetChoiceText( localizedText, tags );
			currentItem.SetType( currListChoiceData.type );
			currentItem.SetDedicatedInput( currListChoiceData.inputActionName );
			currentItem.SetIsPhoneLockActive( m_data.isPhoneLockActive );
			currentItem.SetDimmed( ( ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.Inactive ) || ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.CheckFailed ) ) || ( ( !( ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.QuestImportant ) ) && ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.AlreadyRead ) ) && !( ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.Glowline ) ) ) );
			currentItem.SetSelected( m_dialogHubData.m_isSelected && ( m_dialogHubData.m_selectedInd == i ) );
			currentItem.SetData( m_dialogHubData.m_currentNum + i, m_dialogHubData.m_argTotalCountAcrossHubs, m_dialogHubData.m_hasAboveElements, m_dialogHubData.m_hasBelowElements );
			currentItem.SetVisible( true );
			if( ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.PossessedDialog ) )
			{
				isPossessed = true;
			}
			if( ChoiceTypeWrapper.IsType( currListChoiceData.type, gameinteractionsChoiceType.Glowline ) )
			{
				currentItem.SetGlowline();
			}
			if( currListChoiceData.timeProvider )
			{
				isTimed = !( m_dialogHubData.m_hasAboveElements );
				timedProgress = currListChoiceData.timeProvider.GetCurrentProgress();
				timedDuration = currListChoiceData.timeProvider.GetDuration();
			}
			if( m_data.timeProvider )
			{
				isTimed = !( m_dialogHubData.m_hasAboveElements );
				timedProgress = m_data.timeProvider.GetCurrentProgress();
				timedDuration = m_data.timeProvider.GetDuration();
			}
			currentItem.SetCaptionParts( currListChoiceData.captionParts.parts );
			currentItem.UpdateView();
			currentItem.AnimateSelection();
			if( !( m_dialogHubData.m_isSelected ) )
			{
				currentItem.SetSelected( false );
			}
		}
		SetupTimeBar( isTimed, timedDuration, timedProgress );
		m_rootWidget.SetOpacity( 1.0 );
		SetupTitle( m_data.title, m_dialogHubData.m_isSelected, isPossessed );
		m_isSelected = m_dialogHubData.m_isSelected;
		m_lastSelectedIdx = m_dialogHubData.m_selectedInd;
	}

	public function FadeOutItems( fadeOutTime : Float )
	{
		var i, count : Int32;
		if( m_isClosingDelayed )
		{
			return;
		}
		m_isClosingDelayed = true;
		count = m_itemControllers.Size();
		if( count == 1 )
		{
			m_itemControllers[ i ].SetSelected( true );
		}
		for( i = 0; i < count; i += 1 )
		{
			if( m_lastSelectedIdx == i )
			{
				m_itemControllers[ i ].SetSelected( true );
			}
			m_itemControllers[ i ].FadeOut( fadeOutTime );
		}
	}

	public function GetId() : Int32
	{
		return m_id;
	}

	public function OverrideInputButton( overrideButton : Bool )
	{
		if( m_itemControllers.Size() > 0 )
		{
			m_itemControllers[ 0 ].OverrideInputButton( overrideButton );
		}
	}

	public function WasTimed() : Bool
	{
		return m_wasTimmed;
	}

	private function SetupTimeBar( isActive : Bool, timedDuration : Float, timedProgress : Float )
	{
		var timerParent : inkCompoundWidget;
		if( isActive )
		{
			if( !( m_hasProgressBar ) )
			{
				m_hasProgressBar = true;
				m_wasTimmed = true;
				m_progressBar = ( ( DialogChoiceTimerController )( SpawnFromLocal( inkWidgetRef.Get( m_progressBarHolder ), 'progress_bar' ).GetController() ) );
				m_progressBar.StartProgressBarAnim( timedDuration, timedProgress );
			}
		}
		else if( m_hasProgressBar )
		{
			timerParent = ( ( inkCompoundWidget )( inkWidgetRef.Get( m_progressBarHolder ) ) );
			m_hasProgressBar = false;
			timerParent.RemoveChild( m_progressBar.GetRootWidget() );
		}
	}

	private function SetupTitle( const title : ref< String >, isActive : Bool, isPossessed : Bool )
	{
		m_titleContainer.SetVisible( true );
		m_titleWidget.SetLetterCase( textLetterCase.UpperCase );
		m_titleWidget.SetText( title );
		m_titleContainer.SetState( ( ( isActive && isPossessed ) ? ( 'PossessedDialog' ) : ( 'Default' ) ) );
		m_titleBorder.SetVisible( ( ( isActive && !( isPossessed ) ) && ( StrLen( title ) > 0 ) ) && title != " " );
		m_possessedDialogFluff.SetVisible( isPossessed );
	}

}

class DialogChoiceLogicController extends inkLogicController
{
	private editable var m_InputViewRef : inkWidgetRef;
	private editable var m_VerticalLineWidget : inkWidgetRef;
	private editable var m_ActiveTextRef : inkTextRef;
	private editable var m_InActiveTextRootRef : inkWidgetRef;
	private editable var m_TextFlexRef : inkWidgetRef;
	private editable var m_SelectedBgRef : inkWidgetRef;
	private editable var m_SelectedBgRefJohnny : inkWidgetRef;
	private editable var m_CaptionHolder : inkCompoundRef;
	private editable var m_SecondaryCaptionHolder : inkCompoundRef;
	private editable var m_RootWidget : weak< inkCompoundWidget >;
	private editable var m_AnimationTime : Float;
	default m_AnimationTime = 0.15;
	private editable var m_AnimationSpeed : Float;
	default m_AnimationSpeed = 500.0f;
	private editable var m_UseConstantSpeed : Bool;
	default m_UseConstantSpeed = false;
	private editable var m_phoneIcon : inkWidgetRef;
	private editable var m_tagWrapper : inkWidgetRef;
	private editable var m_tagSeparator : inkWidgetRef;
	private editable var m_tagTextRef : inkTextRef;
	private var m_TextFlex : weak< inkWidget >;
	private var m_InActiveTextRoot : weak< inkWidget >;
	private var m_SelectedBg : weak< inkWidget >;
	private var m_SelectedBgJohnny : weak< inkWidget >;
	private var m_InputView : weak< InteractionsInputView >;
	private var m_CaptionControllers : array< weak< CaptionImageIconsLogicController > >;
	private var m_SecondaryCaptionControllers : array< weak< CaptionImageIconsLogicController > >;
	private var m_type : ChoiceTypeWrapper;
	private var m_isSelected : Bool;
	default m_isSelected = false;
	private var m_prevIsSelected : Bool;
	private var m_hasDedicatedInput : Bool;
	private var m_overriddenInput : Bool;
	private var m_isPreserveSelectionFadeOut : Bool;
	default m_isPreserveSelectionFadeOut = false;
	private var m_isPhoneLockActive : Bool;
	private var m_dedicatedInputName : CName;
	private var m_Active : CName;
	private var m_Inactive : CName;
	private var m_Black : CName;
	private var m_questColor : CName;
	private var m_possessedDialog : CName;
	private const var m_ControllerPromptLimit : Int32;
	default m_ControllerPromptLimit = 3;
	private var m_fadingOptionEndTransparency : Float;
	default m_fadingOptionEndTransparency = 0.1;
	private var m_animSelectedBgProxy : inkAnimProxy;
	private var m_animSelectedJohnnyBgProxy : inkAnimProxy;
	private var m_animActiveTextProxy : inkAnimProxy;
	private var m_animfFadingOutProxy : inkAnimProxy;
	private var m_animIntroProxy : inkAnimProxy;

	protected event OnInitialize()
	{
		m_RootWidget = GetRootCompoundWidget();
		m_InputView = ( ( InteractionsInputView )( inkWidgetRef.GetController( m_InputViewRef ) ) );
		m_InActiveTextRoot = inkWidgetRef.Get( m_InActiveTextRootRef );
		m_TextFlex = inkWidgetRef.Get( m_TextFlexRef );
		m_SelectedBg = inkWidgetRef.Get( m_SelectedBgRef );
		m_SelectedBgJohnny = inkWidgetRef.Get( m_SelectedBgRefJohnny );
		m_Active = 'Active';
		m_Black = 'Black';
		m_questColor = 'Quest';
		m_possessedDialog = 'PossessedDialog';
		m_Inactive = 'Inactive';
		m_animIntroProxy = PlayLibraryAnimation( 'line_intro' );
	}

	public function SetChoiceText( const text : ref< String >, const tag : ref< String > )
	{
		inkTextRef.SetText( m_ActiveTextRef, text );
		inkTextRef.SetText( m_tagTextRef, tag );
		if( tag != "" && text != "" )
		{
			inkTextRef.SetVisible( m_tagTextRef, true );
			inkWidgetRef.SetVisible( m_tagSeparator, true );
			inkTextRef.SetVisible( m_ActiveTextRef, true );
		}
		else if( tag == "" && text != "" )
		{
			inkTextRef.SetVisible( m_tagTextRef, false );
			inkWidgetRef.SetVisible( m_tagSeparator, false );
			inkTextRef.SetVisible( m_ActiveTextRef, true );
		}
		else if( tag != "" && text == "" )
		{
			inkTextRef.SetVisible( m_tagTextRef, true );
			inkWidgetRef.SetVisible( m_tagSeparator, false );
			inkTextRef.SetVisible( m_ActiveTextRef, false );
		}
		else
		{
		}
	}

	public function SetDedicatedInput( value : CName )
	{
		m_hasDedicatedInput = value != '' && value != 'None';
		m_dedicatedInputName = value;
	}

	public function SetIsPhoneLockActive( value : Bool )
	{
		m_isPhoneLockActive = value;
	}

	public function SetType( value : ChoiceTypeWrapper )
	{
		m_type = value;
	}

	public function SetSelected( isSelected : Bool )
	{
		m_prevIsSelected = m_isSelected;
		m_isSelected = isSelected;
	}

	public function SetData( currentNum : Int32, allItemsNum : Int32, hasAbove : Bool, hasBelow : Bool )
	{
		m_InputView.Setup( currentNum, allItemsNum, hasAbove, hasBelow );
		UpdateView();
	}

	public function OverrideInputButton( overrideButton : Bool )
	{
		m_overriddenInput = overrideButton;
		UpdateView();
	}

	public function FadeOut( fadeOutTime : Float )
	{
		m_isPreserveSelectionFadeOut = true;
		if( m_prevIsSelected || m_isSelected )
		{
			if( m_animActiveTextProxy.IsPlaying() )
			{
				m_animActiveTextProxy.Stop();
			}
			if( m_animSelectedBgProxy.IsPlaying() )
			{
				m_animSelectedBgProxy.Stop();
			}
			if( m_animSelectedJohnnyBgProxy && m_animSelectedJohnnyBgProxy.IsPlaying() )
			{
				m_animSelectedJohnnyBgProxy.Stop();
			}
			Fade( m_RootWidget.GetOpacity(), 1.0, 0.22 );
			return;
		}
		Fade( m_RootWidget.GetOpacity(), 0.01, fadeOutTime );
	}

	public function SetFadingState( isFading : Bool, timedDuration : Float, timedProgress : Float, progressBar : weak< inkWidget > )
	{
		if( isFading )
		{
			Fade( 1.0 - timedProgress, 0.0, timedDuration * ( 1.0 - timedProgress ) );
			progressBar.SetVisible( false );
		}
	}

	public function SetVisible( visible : Bool )
	{
		m_RootWidget.SetVisible( visible );
	}

	private function Fade( startValue : Float, endValue : Float, fadeOutTime : Float )
	{
		var animTransparencyInterp : inkAnimTransparency;
		var animFadeOut : inkAnimDef;
		if( m_animfFadingOutProxy.IsPlaying() )
		{
			m_animfFadingOutProxy.Stop();
		}
		animFadeOut = new inkAnimDef;
		animTransparencyInterp = new inkAnimTransparency;
		animTransparencyInterp.SetStartDelay( 0.0 );
		animTransparencyInterp.SetStartTransparency( startValue );
		animTransparencyInterp.SetEndTransparency( endValue );
		animTransparencyInterp.SetDuration( fadeOutTime );
		animFadeOut.AddInterpolator( animTransparencyInterp );
		m_animfFadingOutProxy = m_RootWidget.PlayAnimation( animFadeOut );
	}

	private function ResizeCaptionParts( newSize : Int32 )
	{
		var controller : weak< CaptionImageIconsLogicController >;
		var currentSize : Int32;
		currentSize = m_CaptionControllers.Size();
		if( currentSize < newSize )
		{
			while( m_CaptionControllers.Size() < newSize )
			{
				controller = ( ( CaptionImageIconsLogicController )( SpawnFromLocal( inkCompoundRef.Get( m_CaptionHolder ), 'CaptionImageItems' ).GetController() ) );
				m_CaptionControllers.PushBack( controller );
			}
			while( m_SecondaryCaptionControllers.Size() < newSize )
			{
				controller = ( ( CaptionImageIconsLogicController )( SpawnFromLocal( inkCompoundRef.Get( m_SecondaryCaptionHolder ), 'CaptionImageItems' ).GetController() ) );
				m_SecondaryCaptionControllers.PushBack( controller );
			}
		}
		if( currentSize > newSize )
		{
			if( newSize == 0 )
			{
				m_CaptionControllers.Clear();
				inkCompoundRef.RemoveAllChildren( m_CaptionHolder );
				m_SecondaryCaptionControllers.Clear();
				inkCompoundRef.RemoveAllChildren( m_SecondaryCaptionHolder );
			}
			else
			{
				while( m_CaptionControllers.Size() > newSize )
				{
					m_CaptionControllers.PopBack();
					inkCompoundRef.RemoveChildByIndex( m_CaptionHolder, inkCompoundRef.GetNumChildren( m_CaptionHolder ) - 1 );
				}
				while( m_SecondaryCaptionControllers.Size() > newSize )
				{
					m_SecondaryCaptionControllers.PopBack();
					inkCompoundRef.RemoveChildByIndex( m_SecondaryCaptionHolder, inkCompoundRef.GetNumChildren( m_SecondaryCaptionHolder ) - 1 );
				}
			}
		}
	}

	private function HideAllCaptionParts()
	{
		var i : Int32;
		for( i = 0; i < m_CaptionControllers.Size(); i = i + 1 )
		{
			m_CaptionControllers[ i ].HideAllHolders();
		}
		for( i = 0; i < m_SecondaryCaptionControllers.Size(); i = i + 1 )
		{
			m_SecondaryCaptionControllers[ i ].HideAllHolders();
		}
	}

	public function SetCaptionParts( const argList : ref< array< InteractionChoiceCaptionPart > > )
	{
		var i : Int32;
		var currType : gamedataChoiceCaptionPartType;
		var currController : weak< CaptionImageIconsLogicController >;
		var currentSecondaryController : weak< CaptionImageIconsLogicController >;
		var currBluelineHolder : weak< InteractionChoiceCaptionBluelinePart >;
		ResizeCaptionParts( argList.Size() );
		HideAllCaptionParts();
		for( i = 0; i < argList.Size(); i = i + 1 )
		{
			currController = ( ( CaptionImageIconsLogicController )( m_CaptionControllers[ i ] ) );
			currentSecondaryController = ( ( CaptionImageIconsLogicController )( m_SecondaryCaptionControllers[ i ] ) );
			currType = ( ( InteractionChoiceCaptionPart )( argList[ i ] ) ).GetType();
			if( currType == gamedataChoiceCaptionPartType.Icon )
			{
				currController.SetGenericIcon( ( ( InteractionChoiceCaptionIconPart )( argList[ i ] ) ).iconRecord );
				currentSecondaryController.HideAllHolders();
			}
			else if( currType == gamedataChoiceCaptionPartType.Blueline )
			{
				currBluelineHolder = ( ( InteractionChoiceCaptionBluelinePart )( argList[ i ] ) );
				if( ( ( LifePathBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) )
				{
					currController.SetLifePath( ( ( LifePathBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) );
				}
				else if( ( ( BuildBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) )
				{
					currentSecondaryController.SetSkillCheck( ( ( BuildBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) );
				}
				else if( ( ( PaymentBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) )
				{
					currController.SetPaymentCheck( ( ( PaymentBluelinePart )( currBluelineHolder.blueline.parts[ 0 ] ) ) );
				}
			}
		}
	}

	public function UpdateView()
	{
		if( m_overriddenInput )
		{
			m_InputView.SetInputButton( 'dpad_up_down' );
		}
		else
		{
			if( m_hasDedicatedInput )
			{
				m_InputView.SetInputButton( 'y_wide' );
			}
			else if( IsNameValid( m_dedicatedInputName ) )
			{
				m_InputView.SetInputButton( m_dedicatedInputName );
			}
			else
			{
				m_InputView.ResetInputButton();
			}
		}
		m_InputView.ShowArrows( !( m_overriddenInput ) );
		m_InputView.SetVisible( ( m_isSelected || m_hasDedicatedInput ) || m_overriddenInput );
		inkWidgetRef.SetVisible( m_VerticalLineWidget, !( m_isSelected ) );
		UpdateColors();
	}

	private function UpdateColors()
	{
		var i : Int32;
		var backgroundColor, iconColor : CName;
		if( ChoiceTypeWrapper.IsType( m_type, gameinteractionsChoiceType.QuestImportant ) )
		{
			iconColor = m_questColor;
			backgroundColor = ( ( m_isSelected ) ? ( m_questColor ) : ( m_Black ) );
		}
		else if( ChoiceTypeWrapper.IsType( m_type, gameinteractionsChoiceType.PossessedDialog ) )
		{
			iconColor = m_possessedDialog;
			backgroundColor = ( ( m_isSelected ) ? ( m_possessedDialog ) : ( m_Black ) );
		}
		else
		{
			iconColor = m_Active;
			backgroundColor = ( ( m_isSelected ) ? ( m_Active ) : ( m_Black ) );
		}
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_CaptionHolder ); i = i + 1 )
		{
			if( m_isSelected )
			{
				( ( CaptionImageIconsLogicController )( inkCompoundRef.GetWidgetByIndex( m_CaptionHolder, i ).GetController() ) ).SetSelectedColor( backgroundColor, m_Black );
			}
			else
			{
				( ( CaptionImageIconsLogicController )( inkCompoundRef.GetWidgetByIndex( m_CaptionHolder, i ).GetController() ) ).SetSelectedColor( backgroundColor, iconColor );
			}
		}
		inkWidgetRef.SetVisible( m_VerticalLineWidget, !( m_isSelected ) );
		inkWidgetRef.SetState( m_VerticalLineWidget, iconColor );
		inkWidgetRef.SetState( m_SelectedBgRef, iconColor );
		inkWidgetRef.SetState( m_SelectedBgRefJohnny, iconColor );
		inkWidgetRef.SetVisible( m_phoneIcon, m_isPhoneLockActive );
		if( m_isPhoneLockActive )
		{
			inkTextRef.SetState( m_ActiveTextRef, m_Inactive );
			inkWidgetRef.SetState( m_tagWrapper, m_Inactive );
		}
		else if( m_isSelected )
		{
			inkTextRef.SetState( m_ActiveTextRef, m_Black );
			inkWidgetRef.SetState( m_tagWrapper, m_Black );
		}
		else
		{
			inkTextRef.SetState( m_ActiveTextRef, iconColor );
			inkWidgetRef.SetState( m_tagWrapper, iconColor );
		}
	}

	public function SetGlowline() {}

	public function SetDimmed( value : Bool )
	{
		var opacity : Float;
		opacity = ( ( value ) ? ( 0.40000001 ) : ( 1.0 ) );
		inkTextRef.SetOpacity( m_ActiveTextRef, opacity );
		inkWidgetRef.SetOpacity( m_tagWrapper, opacity );
		m_SelectedBg.SetOpacity( opacity );
	}

	public function SetButtonPromptTextureFromHub( value : CName )
	{
		if( !( m_hasDedicatedInput ) )
		{
			m_dedicatedInputName = value;
		}
	}

	public function AnimateSelection()
	{
		var animSelect, animSelectBg : inkAnimDef;
		var animEffectInterp, animBgEffectInterp : inkAnimEffect;
		var timeConstantSpeed : Float;
		var containerSize : Vector2;
		var startValue, endValue : Float;
		var adjustedTime : Float;
		if( m_prevIsSelected == m_isSelected || m_isPreserveSelectionFadeOut )
		{
			return;
		}
		containerSize = m_InActiveTextRoot.GetDesiredSize();
		startValue = m_InActiveTextRoot.GetEffectParamValue( inkEffectType.LinearWipe, 'LinearWipe_0', 'transition' );
		endValue = ( ( m_isSelected ) ? ( 1.0 ) : ( 0.0 ) );
		adjustedTime = AbsF( endValue - startValue ) * m_AnimationTime;
		timeConstantSpeed = ( AbsF( endValue - startValue ) * ( containerSize.X / m_AnimationSpeed ) ) * m_AnimationTime;
		if( m_UseConstantSpeed )
		{
			adjustedTime = timeConstantSpeed;
		}
		if( m_animActiveTextProxy && m_animActiveTextProxy.IsPlaying() )
		{
			m_animActiveTextProxy.Stop();
		}
		if( startValue != endValue )
		{
			animSelect = new inkAnimDef;
			animEffectInterp = new inkAnimEffect;
			animEffectInterp.SetStartDelay( 0.0 );
			animEffectInterp.SetEffectType( inkEffectType.LinearWipe );
			animEffectInterp.SetEffectName( 'LinearWipe_0' );
			animEffectInterp.SetParamName( 'transition' );
			animEffectInterp.SetStartValue( startValue );
			animEffectInterp.SetEndValue( endValue );
			animEffectInterp.SetDuration( adjustedTime );
			animSelect.AddInterpolator( animEffectInterp );
		}
		m_InActiveTextRoot.SetEffectEnabled( inkEffectType.LinearWipe, 'LinearWipe_0', true );
		m_animActiveTextProxy = m_InActiveTextRoot.PlayAnimation( animSelect );
		if( m_animSelectedBgProxy && m_animSelectedBgProxy.IsPlaying() )
		{
			m_animSelectedBgProxy.Stop();
		}
		if( m_animSelectedJohnnyBgProxy && m_animSelectedJohnnyBgProxy.IsPlaying() )
		{
			m_animSelectedJohnnyBgProxy.Stop();
		}
		if( startValue != endValue )
		{
			animSelectBg = new inkAnimDef;
			animBgEffectInterp = new inkAnimEffect;
			animBgEffectInterp.SetStartDelay( 0.0 );
			animBgEffectInterp.SetEffectType( inkEffectType.LinearWipe );
			animBgEffectInterp.SetEffectName( 'LinearWipe_0' );
			animBgEffectInterp.SetParamName( 'transition' );
			animBgEffectInterp.SetStartValue( startValue );
			animBgEffectInterp.SetEndValue( endValue );
			animBgEffectInterp.SetDuration( adjustedTime );
			animSelectBg.AddInterpolator( animBgEffectInterp );
		}
		m_SelectedBg.SetEffectEnabled( inkEffectType.LinearWipe, 'LinearWipe_0', true );
		m_SelectedBgJohnny.SetEffectEnabled( inkEffectType.LinearWipe, 'LinearWipe_0', true );
		m_animSelectedBgProxy = m_SelectedBg.PlayAnimation( animSelectBg );
		m_animSelectedJohnnyBgProxy = m_SelectedBgJohnny.PlayAnimation( animSelectBg );
	}

}

class CaptionImageIconsLogicController extends inkLogicController
{
	[ category = "Generic" ]
	private editable var m_GenericIcon : inkImageRef;
	[ category = "Generic" ]
	private editable var m_GenericHolder : inkCompoundRef;
	[ category = "Life Path" ]
	private editable var m_LifeIcon : inkImageRef;
	[ category = "Life Path" ]
	private editable var m_LifeDescriptionText : inkTextRef;
	[ category = "Life Path" ]
	private editable var m_LifeBackground : inkWidgetRef;
	[ category = "Life Path" ]
	private editable var m_LifeBackgroundFail : inkWidgetRef;
	[ tooltip = "Wrapper for Lifepath icon + text + separator" ][ category = "Life Path" ]
	private editable var m_LifeWrapper : inkCompoundRef;
	[ tooltip = "Container for whole Life Path container" ][ category = "Life Path" ]
	private editable var m_LifeHolder : inkCompoundRef;
	[ category = "Skill Check" ]
	private editable var m_CheckIcon : inkImageRef;
	[ category = "Skill Check" ]
	private editable var m_CheckText : inkTextRef;
	[ category = "Skill Check" ]
	private editable var m_CheckHolder : inkCompoundRef;
	[ category = "Skill Check" ]
	private editable var m_CheckBackground : inkWidgetRef;
	[ category = "Skill Check" ]
	private editable var m_CheckBackgroundFail : inkWidgetRef;
	[ category = "Pay" ]
	private editable var m_PayIcon : inkImageRef;
	[ category = "Pay" ]
	private editable var m_PayText : inkTextRef;
	[ category = "Pay" ]
	private editable var m_PayBackground : inkWidgetRef;
	[ category = "Pay" ]
	private editable var m_PayBackgroundFail : inkWidgetRef;
	[ tooltip = "Wrapper for  Pay icon + amount + separator" ][ category = "Pay" ]
	private editable var m_PayWrapper : inkCompoundRef;
	[ tooltip = "Container for whole Pay container" ][ category = "Pay" ]
	private editable var m_PayHolder : inkCompoundRef;

	protected event OnInitialize()
	{
		inkCompoundRef.SetVisible( m_LifeHolder, false );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, false );
		inkCompoundRef.SetVisible( m_GenericHolder, false );
	}

	public function ShouldShowFluffIcon() : Bool
	{
		return !( ( ( inkCompoundRef.IsVisible( m_LifeHolder ) || inkCompoundRef.IsVisible( m_CheckHolder ) ) || inkCompoundRef.IsVisible( m_PayHolder ) ) || inkCompoundRef.IsVisible( m_GenericHolder ) );
	}

	public function SetSelectedColor( backgroundColor : CName, iconColor : CName )
	{
		GetRootWidget().SetState( backgroundColor );
		inkImageRef.SetState( m_GenericIcon, iconColor );
		inkImageRef.SetState( m_CheckIcon, iconColor );
		inkTextRef.SetState( m_CheckText, iconColor );
		inkCompoundRef.SetState( m_LifeWrapper, iconColor );
		inkCompoundRef.SetState( m_PayWrapper, iconColor );
	}

	public function SetGenericIcon( iconRecord : weak< ChoiceCaptionIconPart_Record > )
	{
		var iconID : TweakDBID;
		var invalidIconID : TweakDBID;
		var iconTexturePart : CName;
		inkCompoundRef.SetVisible( m_LifeHolder, false );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, false );
		invalidIconID = T"ChoiceCaptionParts.None";
		iconID = iconRecord.TexturePartID().GetID();
		if( ( iconID != invalidIconID ) && TDBID.IsValid( iconID ) )
		{
			SetTexture( m_GenericIcon, iconID );
			inkCompoundRef.SetVisible( m_GenericHolder, true );
		}
		else
		{
			iconTexturePart = MappinUIUtils.MappinToTexturePart( iconRecord.MappinVariant().Type() );
			if( iconTexturePart != 'invalid' )
			{
				inkImageRef.SetTexturePart( m_GenericIcon, iconTexturePart );
				inkCompoundRef.SetVisible( m_GenericHolder, true );
			}
		}
	}

	public function SetLifePath( argData : LifePathBluelinePart )
	{
		var lifePathIconID : TweakDBID;
		inkCompoundRef.SetVisible( m_LifeHolder, true );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, false );
		inkCompoundRef.SetVisible( m_GenericHolder, false );
		lifePathIconID = argData.m_record.CaptionIcon().TexturePartID().GetID();
		if( TDBID.IsValid( lifePathIconID ) )
		{
			SetTexture( m_LifeIcon, lifePathIconID );
			inkCompoundRef.SetVisible( m_LifeHolder, true );
		}
		inkTextRef.SetLocalizedTextScript( m_LifeDescriptionText, argData.m_record.DisplayName() );
		inkWidgetRef.SetOpacity( m_LifeBackground, 0.5 );
		inkWidgetRef.SetOpacity( m_LifeBackgroundFail, 0.5 );
		inkWidgetRef.SetVisible( m_LifeBackground, argData.passed );
		inkWidgetRef.SetVisible( m_LifeBackgroundFail, !( argData.passed ) );
		if( !( argData.passed ) )
		{
			GetRootWidget().SetVisible( false );
		}
	}

	public function SetSkillCheck( argData : BuildBluelinePart )
	{
		var skillIconID : TweakDBID;
		inkCompoundRef.SetVisible( m_LifeHolder, false );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, false );
		inkCompoundRef.SetVisible( m_GenericHolder, false );
		if( argData.passed )
		{
			inkTextRef.SetText( m_CheckText, IntToString( argData.m_lhsValue ) );
		}
		else
		{
			inkTextRef.SetText( m_CheckText, ( argData.m_lhsValue + " / " ) + argData.m_rhsValue );
		}
		inkWidgetRef.SetOpacity( m_CheckBackground, 0.5 );
		inkWidgetRef.SetOpacity( m_CheckBackgroundFail, 0.5 );
		inkWidgetRef.SetVisible( m_CheckBackground, argData.passed );
		inkWidgetRef.SetVisible( m_CheckBackgroundFail, !( argData.passed ) );
		skillIconID = argData.m_record.CaptionIcon().TexturePartID().GetID();
		if( TDBID.IsValid( skillIconID ) )
		{
			SetTexture( m_CheckIcon, skillIconID );
			inkCompoundRef.SetVisible( m_CheckHolder, true );
		}
	}

	public function SetPaymentCheck( argData : PaymentBluelinePart )
	{
		inkCompoundRef.SetVisible( m_LifeHolder, false );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, true );
		inkCompoundRef.SetVisible( m_GenericHolder, false );
		inkTextRef.SetText( m_PayText, IntToString( argData.m_paymentMoney ) );
		inkWidgetRef.SetOpacity( m_PayBackground, 0.5 );
		inkWidgetRef.SetOpacity( m_PayBackgroundFail, 0.5 );
		inkWidgetRef.SetVisible( m_PayBackground, argData.passed );
		inkWidgetRef.SetVisible( m_PayBackgroundFail, !( argData.passed ) );
	}

	public function HideAllHolders()
	{
		inkCompoundRef.SetVisible( m_LifeHolder, false );
		inkCompoundRef.SetVisible( m_CheckHolder, false );
		inkCompoundRef.SetVisible( m_PayHolder, false );
		inkCompoundRef.SetVisible( m_GenericHolder, false );
	}

}

class DialogChoiceTimerController extends inkLogicController
{
	editable var m_bar : inkWidgetRef;
	editable var m_timerValue : inkTextRef;
	private var m_progressAnimDef : inkAnimDef;
	private var m_timerAnimDef : inkAnimDef;
	private var m_ProgressAnimInterpolator : inkAnimScale;
	private var m_timerAnimInterpolator : inkAnimTransparency;
	private var m_timerAnimProxy : inkAnimProxy;
	private var m_timerBarAnimProxy : inkAnimProxy;
	private var m_AnimOptions : inkAnimOptions;
	private var time : Float;

	protected event OnInitialize()
	{
		inkWidgetRef.SetScale( m_bar, Vector2( 1.0, 1.0 ) );
		SetupAnimation();
		PlayLibraryAnimation( 'bar_intro' );
	}

	protected event OnUninitialize()
	{
		m_timerAnimProxy.Stop();
		m_timerBarAnimProxy.Stop();
		m_timerAnimProxy.UnregisterFromCallback( inkanimEventType.OnEndLoop, this, 'OnTimerEndLoop' );
	}

	public function StartProgressBarAnim( timeDuration : Float, timedProgress : Float )
	{
		m_ProgressAnimInterpolator.SetDuration( ( 1.0 - timedProgress ) * timeDuration );
		m_ProgressAnimInterpolator.SetStartScale( Vector2( 1.0 - timedProgress, 1.0 ) );
		time = m_ProgressAnimInterpolator.GetDuration() - 1.0;
		m_timerBarAnimProxy = inkWidgetRef.PlayAnimation( m_bar, m_progressAnimDef );
	}

	private function SetTime()
	{
		var timeS : String;
		if( time < 10.0 )
		{
			timeS = "00:0" + ( ( String )( RoundF( time ) ) );
		}
		else
		{
			timeS = "00:" + ( ( String )( RoundF( time ) ) );
		}
		inkTextRef.SetText( m_timerValue, timeS );
	}

	protected event OnTimerEndLoop( proxy : inkAnimProxy )
	{
		SetTime();
		if( time < 1.0 )
		{
			m_timerAnimProxy.Stop();
		}
		time = time - 1.0;
	}

	public function OnMenuVisibilityChange( isMenuVisible : Bool )
	{
		if( isMenuVisible )
		{
			m_timerAnimProxy.Pause();
			m_timerBarAnimProxy.Pause();
		}
		else
		{
			m_timerAnimProxy.Resume();
			m_timerBarAnimProxy.Resume();
		}
	}

	private function SetupAnimation()
	{
		SetTime();
		m_progressAnimDef = new inkAnimDef;
		m_ProgressAnimInterpolator = new inkAnimScale;
		m_ProgressAnimInterpolator.SetStartScale( Vector2( 1.0, 1.0 ) );
		m_ProgressAnimInterpolator.SetEndScale( Vector2( 0.0, 1.0 ) );
		m_progressAnimDef.AddInterpolator( m_ProgressAnimInterpolator );
		m_timerAnimDef = new inkAnimDef;
		m_timerAnimInterpolator = new inkAnimTransparency;
		m_timerAnimInterpolator.SetDuration( 1.0 );
		m_timerAnimInterpolator.SetStartTransparency( 1.0 );
		m_timerAnimInterpolator.SetEndTransparency( 1.0 );
		m_timerAnimInterpolator.SetType( inkanimInterpolationType.Linear );
		m_timerAnimInterpolator.SetMode( inkanimInterpolationMode.EasyIn );
		m_timerAnimDef.AddInterpolator( m_timerAnimInterpolator );
		m_AnimOptions.playReversed = false;
		m_AnimOptions.executionDelay = 0.0;
		m_AnimOptions.loopType = inkanimLoopType.Cycle;
		m_AnimOptions.loopInfinite = true;
		m_AnimOptions.dependsOnTimeDilation = true;
		m_timerAnimProxy = GetRootWidget().PlayAnimationWithOptions( m_timerAnimDef, m_AnimOptions );
		m_timerAnimProxy.RegisterToCallback( inkanimEventType.OnEndLoop, this, 'OnTimerEndLoop' );
		m_timerAnimProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnTimerEndLoop' );
	}

}

