class PerkScreenController extends inkLogicController
{
	protected editable var m_hubSelector : inkWidgetRef;
	protected editable var m_connectionLinesContainer : inkCompoundRef;
	protected editable var m_boughtConnectionLinesContainer : inkCompoundRef;
	protected editable var m_maxedConnectionLinesContainer : inkCompoundRef;
	protected editable var m_boughtMaskContainer : inkCanvasRef;
	protected editable var m_maxedMaskContainer : inkCanvasRef;
	protected editable var m_attributeNameText : inkTextRef;
	protected editable var m_attributeLevelText : inkTextRef;
	protected editable var m_levelControllerRef : inkWidgetRef;
	protected editable var m_rewardsControllerRef : inkWidgetRef;
	protected editable var m_TooltipsManagerRef : inkWidgetRef;
	protected editable var m_proficiencyRootRef : inkWidgetRef;
	protected editable var m_proficiencyDescriptionText : inkTextRef;
	protected var m_dataManager : PlayerDevelopmentDataManager;
	protected var m_displayData : AttributeDisplayData;
	private var m_proficiencyRoot : weak< TabRadioGroup >;
	private var m_widgetMap : array< weak< PerkDisplayContainerController > >;
	private var m_traitController : weak< PerkDisplayContainerController >;
	private var m_currentIndex : Int32;
	private var m_connectionLines : Int32[ 45 ];
	private var m_levelController : weak< StatsProgressController >;
	private var m_rewardsController : weak< StatsStreetCredReward >;
	private var m_tooltipsManager : weak< gameuiTooltipsManager >;

	protected event OnInitialize()
	{
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnButtonRelease' );
		m_levelController = ( ( StatsProgressController )( SpawnFromLocal( inkWidgetRef.Get( m_levelControllerRef ), 'SkillLevel' ).GetControllerByType( 'StatsProgressController' ) ) );
		m_rewardsController = ( ( StatsStreetCredReward )( SpawnFromLocal( inkWidgetRef.Get( m_rewardsControllerRef ), 'SkillRewards' ).GetControllerByType( 'StatsStreetCredReward' ) ) );
		m_tooltipsManager = ( ( gameuiTooltipsManager )( inkWidgetRef.GetControllerByType( m_TooltipsManagerRef, 'gameuiTooltipsManager' ) ) );
		m_tooltipsManager.Setup();
		m_proficiencyRoot = ( ( TabRadioGroup )( inkWidgetRef.GetController( m_proficiencyRootRef ) ) );
		m_proficiencyRoot.RegisterToCallback( 'OnValueChanged', this, 'OnValueChanged' );
		m_connectionLines = PerksScreenStaticData.GetPerksConnectionLines();
	}

	protected function RegisterProficiencyButtons( attributeDisplayData : AttributeDisplayData, startingIndex : Int32 )
	{
		var proficienciesSize : Int32;
		var labels : array< String >;
		var i : Int32;
		proficienciesSize = attributeDisplayData.m_proficiencies.Size();
		for( i = 0; i < proficienciesSize; i += 1 )
		{
			labels.PushBack( attributeDisplayData.m_proficiencies[ i ].m_localizedName );
		}
		m_proficiencyRoot.SetData( proficienciesSize, m_tooltipsManager, labels );
		m_proficiencyRoot.Toggle( startingIndex );
	}

	protected event OnUninitialize()
	{
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnButtonRelease' );
	}

	protected event OnSetUserData( userData : IScriptable )
	{
		userData;
	}

	private function GetMenuData( data : ProficiencyDisplayData ) : MenuData
	{
		var menuData : MenuData;
		menuData.identifier = data.m_index;
		menuData.label = data.m_localizedName;
		menuData.userData = data;
		return menuData;
	}

	public function Setup( displayData : AttributeDisplayData, dataManager : PlayerDevelopmentDataManager, startingIndex : Int32 )
	{
		var i : Int32;
		var attributeData : AttributeData;
		m_dataManager = dataManager;
		m_displayData = displayData;
		for( i = 0; i < m_widgetMap.Size(); i += 1 )
		{
			m_widgetMap[ i ].SetData( NULL, NULL );
		}
		RegisterProficiencyButtons( displayData, startingIndex );
		attributeData = dataManager.GetAttribute( displayData.m_attributeId );
		inkTextRef.SetText( m_attributeNameText, attributeData.label );
		inkTextRef.SetText( m_attributeLevelText, IntToString( attributeData.value ) );
		RebuildPerks( startingIndex );
		PlayLibraryAnimation( 'start_perk_screen' );
	}

	public function RebuildPerks( index : Int32 )
	{
		var proficiency : ProficiencyDisplayData;
		var area : AreaDisplayData;
		var perk : PerkDisplayData;
		var i, j : Int32;
		var controller : weak< PerkDisplayContainerController >;
		var perksCount : Int32;
		var isLineVisible : Bool;
		m_currentIndex = index;
		perksCount = 0;
		inkCanvasRef.RemoveAllChildren( m_boughtMaskContainer );
		inkCanvasRef.RemoveAllChildren( m_maxedMaskContainer );
		proficiency = m_displayData.m_proficiencies[ index ];
		for( i = 0; i < proficiency.m_areas.Size(); i += 1 )
		{
			area = proficiency.m_areas[ i ];
			for( j = 0; j < area.m_perks.Size(); j += 1 )
			{
				perk = area.m_perks[ j ];
				controller = m_widgetMap[ perksCount ];
				controller.SetData( perk, m_dataManager );
				SpawnConnectionGradiantMask( controller );
				perksCount += 1;
			}
		}
		if( m_traitController != NULL )
		{
			m_traitController.SetData( proficiency.m_traitData, m_dataManager );
		}
		m_levelController.SetProfiencyLevel( proficiency );
		m_rewardsController.SetData( proficiency, m_tooltipsManager, 0 );
		for( i = 0; i <= m_connectionLines.Size(); i += 1 )
		{
			isLineVisible = m_connectionLines[ i ] <= perksCount;
			ShowLineWidget( m_connectionLinesContainer, isLineVisible, i );
			ShowLineWidget( m_boughtConnectionLinesContainer, isLineVisible, i );
			ShowLineWidget( m_maxedConnectionLinesContainer, isLineVisible, i );
		}
		for( i = perksCount; i < m_widgetMap.Size(); i += 1 )
		{
			controller = m_widgetMap[ i ];
			controller.SetData( NULL, NULL );
		}
		inkTextRef.SetText( m_proficiencyDescriptionText, proficiency.m_localizedDescription );
	}

	protected event OnUnlimitedUnlocked( evt : UnlimitedUnlocked )
	{
		if( m_traitController != NULL )
		{
			m_traitController.PlayLibraryAnimation( 'reveal_unlimited_perk_traces' );
		}
	}

	private function ProcessTutorialFact()
	{
		var questSystem : QuestsSystem;
		questSystem = GameInstance.GetQuestsSystem( m_dataManager.GetPlayer().GetGame() );
		if( ( questSystem.GetFact( 'perks_tutorial' ) == 0 ) && ( questSystem.GetFact( 'disable_tutorials' ) == 0 ) )
		{
			questSystem.SetFact( 'perks_tutorial', 1 );
		}
	}

	private function SpawnConnectionGradiantMask( controller : weak< PerkDisplayContainerController > )
	{
		var data : BasePerkDisplayData;
		var container : inkCanvasRef;
		var widget : weak< inkWidget >;
		var position : inkMargin;
		data = controller.GetPerkDisplayData();
		if( data.m_locked || ( data.m_level <= 0 ) )
		{
			return;
		}
		container = ( ( data.m_level == data.m_maxLevel ) ? ( m_maxedMaskContainer ) : ( m_boughtMaskContainer ) );
		widget = SpawnFromLocal( inkCanvasRef.Get( container ), 'ConnectionGradiantMask' );
		if( widget == NULL )
		{
			return;
		}
		position = controller.GetRootWidget().GetMargin();
		position.left += 100.0;
		position.top += 120.0;
		widget.SetMargin( position );
		widget.SetAnchorPoint( Vector2( 0.5, 0.5 ) );
	}

	private function ShowLineWidget( lineContainer : inkCompoundRef, show : Bool, lineNumber : Int32 )
	{
		var line : weak< inkWidget >;
		line = inkCompoundRef.GetWidgetByPath( lineContainer, inkWidgetPath.Build( StringToName( "connect" + IntToString( lineNumber ) ) ) );
		line.SetVisible( show );
	}

	protected event OnValueChanged( controller : weak< inkRadioGroupController >, selectedIndex : Int32 )
	{
		RebuildPerks( ( ( selectedIndex == -1 ) ? ( m_currentIndex ) : ( selectedIndex ) ) );
		PlayLibraryAnimation( 'start_perk_screen' );
	}

	protected event OnPerkBoughtEvent( evt : PerkBoughtEvent )
	{
		var developmentData : PlayerDevelopmentData;
		var proficiencyType : gamedataProficiencyType;
		developmentData = PlayerDevelopmentSystem.GetData( m_dataManager.GetPlayer() );
		proficiencyType = developmentData.GetProficiencyFromPerkArea( developmentData.GetPerkAreaFromPerk( evt.perkType ) );
		m_displayData.m_proficiencies[ m_currentIndex ] = m_dataManager.GetProficiencyWithData( proficiencyType );
		RebuildPerks( m_currentIndex );
	}

	protected event OnTraitBoughtEvent( evt : TraitBoughtEvent )
	{
		var proficiencyType : gamedataProficiencyType;
		proficiencyType = m_displayData.m_proficiencies[ m_currentIndex ].m_proficiency;
		m_displayData.m_proficiencies[ m_currentIndex ] = m_dataManager.GetProficiencyWithData( proficiencyType );
		RebuildPerks( m_currentIndex );
	}

	protected event OnPerkDisplayContainerCreated( evt : PerkDisplayContainerCreatedEvent )
	{
		var controller : PerkDisplayContainerController;
		controller = ( ( PerkDisplayContainerController )( evt.container.GetController() ) );
		if( evt.isTrait )
		{
			m_traitController = controller;
		}
		else if( evt.index > 0 )
		{
			if( m_widgetMap.Size() < evt.index )
			{
				m_widgetMap.Resize( evt.index );
			}
			m_widgetMap[ evt.index - 1 ] = controller;
		}
	}

	public function GetProficiencyDisplayData() : ProficiencyDisplayData
	{
		return m_displayData.m_proficiencies[ m_currentIndex ];
	}

	public function GetHubSelectorWidget() : weak< inkWidget >
	{
		return inkWidgetRef.Get( m_proficiencyRootRef );
	}

}

class PerksSkillLabelController extends HubMenuLabelController
{

	public override function SetTargetData( const data : ref< MenuData >, direction : Int32 )
	{
		m_data = data;
		m_direction = direction;
		if( direction != 0 )
		{
			m_watchForSize = true;
			m_wrapperNextController.SetData( data );
		}
		else
		{
			m_watchForInstatnSize = true;
			m_wrapperController.SetData( data );
		}
	}

	public override function SetActive( active : Bool )
	{
		super.SetActive( active );
	}

}

class PerksSkillLabelContentContainer extends HubMenuLabelContentContainer
{
	protected editable var m_levelLabel : inkTextRef;
	protected editable var m_levelBar : inkWidgetRef;
	var m_skillData : ProficiencyDisplayData;

	public override function SetData( const data : ref< MenuData > )
	{
		m_data = data;
		RefreshSkillData( ( ( ProficiencyDisplayData )( data.userData ) ) );
	}

	private function RefreshSkillData( skill : ProficiencyDisplayData )
	{
		m_skillData = skill;
		m_labelName = m_skillData.m_localizedName;
		inkTextRef.SetText( m_label, m_labelName );
	}

	protected event OnPerkPurchased( evt : PerkBoughtEvent )
	{
		RefreshSkillData( ( ( ProficiencyDisplayData )( m_data.userData ) ) );
	}

}

class PerksScreenStaticData
{

	public static function GetPerksConnectionLines() : Int32[ 45 ]
	{
		var result : Int32[ 45 ];
		result[ 0 ] = 29;
		result[ 1 ] = 17;
		result[ 2 ] = 27;
		result[ 3 ] = 29;
		result[ 4 ] = 21;
		result[ 5 ] = 15;
		result[ 6 ] = 19;
		result[ 7 ] = 19;
		result[ 8 ] = 20;
		result[ 9 ] = 20;
		result[ 10 ] = 14;
		result[ 11 ] = 13;
		result[ 12 ] = 13;
		result[ 13 ] = 9;
		result[ 14 ] = 25;
		result[ 15 ] = 3;
		result[ 16 ] = 9;
		result[ 17 ] = 8;
		result[ 18 ] = 2;
		result[ 19 ] = 7;
		result[ 20 ] = 9;
		result[ 21 ] = 6;
		result[ 22 ] = 6;
		result[ 23 ] = 4;
		result[ 24 ] = 5;
		result[ 25 ] = 5;
		result[ 26 ] = 6;
		result[ 27 ] = 12;
		result[ 28 ] = 12;
		result[ 29 ] = 10;
		result[ 30 ] = 11;
		result[ 31 ] = 12;
		result[ 32 ] = 18;
		result[ 33 ] = 18;
		result[ 34 ] = 28;
		result[ 35 ] = 30;
		result[ 36 ] = 26;
		result[ 37 ] = 24;
		result[ 38 ] = 24;
		result[ 39 ] = 16;
		result[ 40 ] = 18;
		result[ 41 ] = 23;
		result[ 42 ] = 22;
		result[ 43 ] = 22;
		result[ 44 ] = 23;
		return result;
	}

}

class ProficiencyTabButtonController extends TabButtonController
{
	private editable var m_bottom_bar : inkWidgetRef;
	private var m_proxy : inkAnimProxy;
	private var m_isToggledState : Bool;

	protected event OnInitialize()
	{
		super.OnInitialize();
		RegisterToCallback( 'OnToggleChanged', this, 'OnToggleChanged' );
	}

	protected event OnUninitialize()
	{
		UnregisterFromCallback( 'OnToggleChanged', this, 'OnToggleChanged' );
	}

	protected event OnToggleChanged( controller : weak< inkToggleController >, isToggled : Bool )
	{
		var state : inkEToggleState;
		var isToggledState : Bool;
		var buttonColor : CName;
		state = GetToggleState();
		isToggledState = ( state == inkEToggleState.Toggled || state == inkEToggleState.ToggledPress ) || state == inkEToggleState.ToggledHover;
		buttonColor = ( ( isToggledState ) ? ( 'MainColors.ActiveBlue' ) : ( 'MainColors.Red' ) );
		inkWidgetRef.Get( m_bottom_bar ).BindProperty( 'tintColor', buttonColor );
		if( m_isToggledState == isToggledState )
		{
			return false;
		}
		m_isToggledState = isToggledState;
		if( m_proxy )
		{
			m_proxy.Stop( true );
		}
		if( isToggledState )
		{
			m_proxy = PlayLibraryAnimation( 'tab_hover' );
			PlaySound( 'Button', 'OnHover' );
		}
		else
		{
			m_proxy = PlayLibraryAnimation( 'tab_hover_out' );
		}
	}

}

class TabRadioGroup extends inkRadioGroupController
{
	private editable var m_root : inkCompoundRef;
	var toggles : array< weak< TabButtonController > >;
	private var m_TooltipsManager : weak< gameuiTooltipsManager >;

	public function SetData( enumCount : Int32, optional tooltipsManager : weak< gameuiTooltipsManager >, optional labelList : array< String >, optional iconList : array< String > )
	{
		var i : Int32;
		var widget : weak< inkWidget >;
		var tabToggle : TabButtonController;
		m_TooltipsManager = tooltipsManager;
		for( i = 0; i < toggles.Size(); i += 1 )
		{
			widget = toggles[ i ].GetRootWidget();
			widget.SetVisible( false );
		}
		for( i = 0; i < enumCount; i += 1 )
		{
			if( toggles.Size() <= i )
			{
				widget = SpawnFromLocal( inkCompoundRef.Get( m_root ), 'proficiencyTabButton' );
				if( widget == NULL )
				{
					widget = SpawnFromExternal( inkCompoundRef.Get( m_root ), R"base\gameplay\gui\common\components\toggles.inkwidget", 'proficiencyTabButton' );
				}
				tabToggle = ( ( TabButtonController )( widget.GetController() ) );
				toggles.PushBack( tabToggle );
				AddToggle( tabToggle );
			}
			else
			{
				tabToggle = ( ( TabButtonController )( toggles[ i ] ) );
			}
			tabToggle.SetToggleData( i, labelList[ i ], iconList[ i ] );
			widget = tabToggle.GetRootWidget();
			widget.SetVisible( true );
			if( m_TooltipsManager )
			{
				tabToggle.RegisterToCallback( 'OnHoverOver', this, 'OnHoverOver' );
				tabToggle.RegisterToCallback( 'OnHoverOut', this, 'OnHoverOut' );
			}
		}
	}

	protected event OnHoverOver( evt : inkPointerEvent )
	{
		var widget : inkWidget;
		var tooltipData : MessageTooltipData;
		var controller : ToggleController;
		widget = evt.GetCurrentTarget();
		controller = ( ( ToggleController )( widget.GetController() ) );
		tooltipData = new MessageTooltipData;
		tooltipData.Title = GetLocalizedText( controller.GetLabelKey() );
		m_TooltipsManager.ShowTooltip( 1, tooltipData, inkMargin( 60.0, 0.0, 0.0, 0.0 ) );
	}

	protected event OnHoverOut( evt : inkPointerEvent )
	{
		m_TooltipsManager.HideTooltips();
	}

}

class TabButtonController extends inkToggleController
{
	protected editable var m_label : inkTextRef;
	protected editable var m_icon : inkImageRef;
	protected var m_data : Int32;
	protected var m_labelSet : String;
	protected var m_iconSet : String;

	protected event OnInitialize()
	{
		RegisterToCallback( 'OnRelease', this, 'OnTabSelected' );
		RegisterToCallback( 'OnHoverOver', this, 'OnTabHoverOver' );
		RegisterToCallback( 'OnHoverOut', this, 'OnTabHoverOut' );
	}

	public function SetToggleData( data : Int32, optional label : String, optional icon : String )
	{
		m_data = data;
		m_labelSet = label;
		m_iconSet = icon;
		if( inkTextRef.IsValid( m_label ) )
		{
			inkTextRef.SetText( m_label, GetLabelKey() );
		}
		if( inkImageRef.IsValid( m_icon ) )
		{
			InkImageUtils.RequestSetImage( this, m_icon, GetIcon(), 'OnIconCallback' );
		}
	}

	protected event OnIconCallback( e : iconAtlasCallbackData )
	{
		if( e.loadResult != inkIconResult.Success )
		{
			inkImageRef.SetTexturePart( m_icon, StringToName( m_iconSet ) );
		}
	}

	public function GetData() : Int32
	{
		return m_data;
	}

	public virtual function GetLabelKey() : String
	{
		if( IsStringValid( m_labelSet ) )
		{
			return m_labelSet;
		}
		return "";
	}

	public virtual function GetIcon() : String
	{
		if( IsStringValid( m_iconSet ) )
		{
			return m_iconSet;
		}
		return "";
	}

	protected event OnTabSelected( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			PlaySound( 'Button', 'OnPress' );
		}
	}

	protected event OnTabHoverOver( e : inkPointerEvent ) {}

	protected event OnTabHoverOut( e : inkPointerEvent ) {}
}

