class StatsMainGameController extends gameuiMenuGameController
{
	private editable var m_MainViewRoot : inkWidgetRef;
	private editable var m_statsList : inkCompoundRef;
	private editable var m_TooltipsManagerRef : inkWidgetRef;
	private editable var m_levelControllerRef : inkWidgetRef;
	private editable var m_streetCredControllerRef : inkWidgetRef;
	private editable var m_detailListControllerRef : inkWidgetRef;
	private editable var m_statsStreetCredRewardRef : inkWidgetRef;
	private editable var m_statsPlayTimeControllerdRef : inkWidgetRef;
	private editable var m_btnInventory : inkWidgetRef;
	private editable var m_buttonHintsManagerRef : inkWidgetRef;
	private editable var m_rightPanelFluff1 : inkWidgetRef;
	private editable var m_rightPanelFluff2 : inkWidgetRef;
	private var m_TooltipsManager : weak< gameuiTooltipsManager >;
	private var m_InventoryManager : InventoryDataManagerV2;
	private var m_player : weak< PlayerPuppet >;
	private var m_healthStatsData : array< StatViewData >;
	private var m_DPSStatsData : array< StatViewData >;
	private var m_armorStatsData : array< StatViewData >;
	private var m_otherStatsData : array< StatViewData >;
	private var playerStatsBlackboard : weak< IBlackboard >;
	private var currencyListener : CallbackHandle;
	private var characterCredListener : CallbackHandle;
	private var characterLevelListener : CallbackHandle;
	private var characterCurrentXPListener : CallbackHandle;
	private var characterCredPointsListener : CallbackHandle;
	private var m_PDS : PlayerDevelopmentSystem;
	private var m_levelController : weak< StatsProgressController >;
	private var m_streetCredController : weak< StatsProgressController >;
	private var m_detailListController : weak< StatsDetailListController >;
	private var m_statsStreetCredReward : weak< StatsStreetCredReward >;
	private var m_statsPlayTimeController : weak< StatsPlayTimeController >;
	private var m_previousMenuData : PreviousMenuData;
	private var m_buttonHintsController : weak< ButtonHints >;
	private var m_animProxy : inkAnimProxy;

	protected event OnInitialize()
	{
		var gameInstanace : GameInstance;
		var gameTime : EngineTime;
		var playbackOptions : inkAnimOptions;
		gameInstanace = GetPlayerControlledObject().GetGame();
		gameTime = GameInstance.GetPlaythroughTime( gameInstanace );
		m_TooltipsManager = ( ( gameuiTooltipsManager )( inkWidgetRef.GetControllerByType( m_TooltipsManagerRef, 'gameuiTooltipsManager' ) ) );
		m_levelController = ( ( StatsProgressController )( inkWidgetRef.GetControllerByType( m_levelControllerRef, 'StatsProgressController' ) ) );
		m_streetCredController = ( ( StatsProgressController )( inkWidgetRef.GetControllerByType( m_streetCredControllerRef, 'StatsProgressController' ) ) );
		m_detailListController = ( ( StatsDetailListController )( inkWidgetRef.GetControllerByType( m_detailListControllerRef, 'StatsDetailListController' ) ) );
		m_statsStreetCredReward = ( ( StatsStreetCredReward )( inkWidgetRef.GetControllerByType( m_statsStreetCredRewardRef, 'StatsStreetCredReward' ) ) );
		m_statsPlayTimeController = ( ( StatsPlayTimeController )( inkWidgetRef.GetControllerByType( m_statsPlayTimeControllerdRef, 'StatsPlayTimeController' ) ) );
		m_player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( gameInstanace ).GetLocalPlayerMainGameObject() ) );
		m_InventoryManager = new InventoryDataManagerV2;
		m_InventoryManager.Initialize( m_player );
		m_InventoryManager.GetPlayerHealthStats( m_healthStatsData );
		m_InventoryManager.GetPlayerDPSStats( m_DPSStatsData );
		m_InventoryManager.GetPlayerArmorStats( m_armorStatsData );
		m_InventoryManager.GetPlayerOtherStats( m_otherStatsData );
		m_TooltipsManager.Setup();
		inkCompoundRef.RemoveAllChildren( m_statsList );
		PopulateStats();
		m_PDS = ( ( PlayerDevelopmentSystem )( GameInstance.GetScriptableSystemsContainer( ( ( GameObject )( GetOwnerEntity() ) ).GetGame() ).Get( 'PlayerDevelopmentSystem' ) ) );
		playerStatsBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_PlayerStats );
		characterLevelListener = playerStatsBlackboard.RegisterDelayedListenerInt( GetAllBlackboardDefs().UI_PlayerStats.Level, this, 'OnCharacterLevelUpdated' );
		playerStatsBlackboard.SignalInt( GetAllBlackboardDefs().UI_PlayerStats.Level );
		characterCurrentXPListener = playerStatsBlackboard.RegisterDelayedListenerInt( GetAllBlackboardDefs().UI_PlayerStats.CurrentXP, this, 'OnCharacterLevelCurrentXPUpdated' );
		playerStatsBlackboard.SignalInt( GetAllBlackboardDefs().UI_PlayerStats.CurrentXP );
		characterCredListener = playerStatsBlackboard.RegisterDelayedListenerInt( GetAllBlackboardDefs().UI_PlayerStats.StreetCredLevel, this, 'OnCharacterStreetCredLevelUpdated' );
		playerStatsBlackboard.SignalInt( GetAllBlackboardDefs().UI_PlayerStats.StreetCredLevel );
		characterCredPointsListener = playerStatsBlackboard.RegisterDelayedListenerInt( GetAllBlackboardDefs().UI_PlayerStats.StreetCredPoints, this, 'OnCharacterStreetCredPointsUpdated' );
		playerStatsBlackboard.SignalInt( GetAllBlackboardDefs().UI_PlayerStats.StreetCredPoints );
		m_statsPlayTimeController.Set( EngineTime.ToFloat( gameTime ), m_PDS.GetLifePath( m_player ) );
		HubMenuUtils.SetMenuHyperlinkData( m_btnInventory, HubMenuItems.Inventory, HubMenuItems.None, 'inventory_screen', 'ico_inventory', 'UI-PanelNames-INVENTORY' );
		m_buttonHintsController = ( ( ButtonHints )( SpawnFromExternal( inkWidgetRef.Get( m_buttonHintsManagerRef ), R"base\gameplay\gui\common\buttonhints.inkwidget", 'Root' ).GetController() ) );
		m_buttonHintsController.AddButtonHint( 'back', GetLocalizedText( "Common-Access-Close" ) );
		OnIntro();
		PlayLibraryAnimation( 'menu_intro' );
		super.OnInitialize();
		playbackOptions.loopType = inkanimLoopType.Cycle;
		playbackOptions.loopInfinite = true;
		playbackOptions.customTimeDilation = 0.2;
		playbackOptions.applyCustomTimeDilation = true;
		m_animProxy = PlayLibraryAnimation( 'text_wall', playbackOptions );
	}

	protected event OnUninitialize()
	{
		m_InventoryManager.UnInitialize();
		playerStatsBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_PlayerStats.Level, characterLevelListener );
		playerStatsBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_PlayerStats.CurrentXP, characterCurrentXPListener );
		playerStatsBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_PlayerStats.StreetCredLevel, characterCredListener );
		playerStatsBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UI_PlayerStats.StreetCredPoints, characterCredPointsListener );
		super.OnUninitialize();
	}

	protected event OnSetUserData( userData : IScriptable )
	{
		m_previousMenuData = ( ( PreviousMenuData )( userData ) );
	}

	protected event OnCharacterLevelUpdated( value : Int32 )
	{
		m_levelController.SetLevel( value );
	}

	protected event OnCharacterLevelCurrentXPUpdated( value : Int32 )
	{
		var remainingXP : Int32;
		remainingXP = m_PDS.GetRemainingExpForLevelUp( m_player, gamedataProficiencyType.Level );
		m_levelController.SetProgress( value, remainingXP + value );
	}

	protected event OnCharacterStreetCredLevelUpdated( value : Int32 )
	{
		m_streetCredController.SetLevel( value );
		m_statsStreetCredReward.SetData( SteetCredDataHelper.GetData(), m_TooltipsManager, value, 0, "Gameplay-RPG-Skills-StreetCred" );
	}

	protected event OnCharacterStreetCredPointsUpdated( value : Int32 )
	{
		var remainingXP : Int32;
		remainingXP = m_PDS.GetRemainingExpForLevelUp( m_player, gamedataProficiencyType.StreetCred );
		m_streetCredController.SetProgress( value, remainingXP + value );
	}

	public function PopulateStats()
	{
		AddStat( gamedataStatType.EffectiveDPS, m_DPSStatsData );
		AddStat( gamedataStatType.Armor, m_armorStatsData );
		AddStat( gamedataStatType.Health, m_healthStatsData );
		AddStat( gamedataStatType.Invalid, m_otherStatsData );
	}

	private function AddStat( statType : gamedataStatType, const datalist : ref< array< StatViewData > > )
	{
		var statData : StatViewData;
		var statView : weak< StatsViewController >;
		statView = ( ( StatsViewController )( SpawnFromLocal( inkCompoundRef.Get( m_statsList ), 'statView' ).GetControllerByType( 'StatsViewController' ) ) );
		if( statType != gamedataStatType.Invalid )
		{
			statData = RequestStat( statType, datalist );
		}
		else
		{
			statData.type = gamedataStatType.Invalid;
			statData.statName = "LocKey#49347";
		}
		statView.Setup( statData );
	}

	private function OnIntro() {}

	private function RequestStat( stat : gamedataStatType, const datalist : ref< array< StatViewData > > ) : StatViewData
	{
		var data : StatViewData;
		var i : Int32;
		for( i = 0; i < datalist.Size(); i += 1 )
		{
			if( datalist[ i ].type == stat )
			{
				return datalist[ i ];
			}
		}
		return data;
	}

	protected event OnCategoryClicked( evt : CategoryClickedEvent )
	{
		var detailsData : array< StatViewData >;
		inkWidgetRef.SetVisible( m_rightPanelFluff1, false );
		inkWidgetRef.SetVisible( m_rightPanelFluff2, false );
		switch( evt.statsData.type )
		{
			case gamedataStatType.Health:
				detailsData = m_healthStatsData;
			break;
			case gamedataStatType.EffectiveDPS:
				detailsData = m_DPSStatsData;
			break;
			case gamedataStatType.Armor:
				detailsData = m_armorStatsData;
			break;
			case gamedataStatType.Invalid:
				detailsData = m_otherStatsData;
			break;
		}
		m_detailListController.SetData( evt.statsData, detailsData );
	}

}

class StatsViewController extends inkLogicController
{
	private editable var m_StatLabelRef : inkTextRef;
	private editable var m_StatValueRef : inkTextRef;
	private editable var m_icon : inkImageRef;
	private var m_stat : StatViewData;

	protected event OnInitialize()
	{
		this.RegisterToCallback( 'OnHoverOver', this, 'OnButtonClick' );
	}

	public function Setup( const stat : ref< StatViewData > )
	{
		inkTextRef.SetText( m_StatLabelRef, stat.statName );
		inkTextRef.SetText( m_StatValueRef, IntToString( stat.value ) );
		m_stat = stat;
		switch( stat.type )
		{
			case gamedataStatType.Health:
				inkImageRef.SetTexturePart( m_icon, 'health' );
			break;
			case gamedataStatType.EffectiveDPS:
				inkImageRef.SetTexturePart( m_icon, 'gun' );
			break;
			case gamedataStatType.Armor:
				inkImageRef.SetTexturePart( m_icon, 'armor' );
			break;
			case gamedataStatType.Invalid:
				inkImageRef.SetTexturePart( m_icon, 'other' );
			inkTextRef.SetVisible( m_StatValueRef, false );
			break;
		}
	}

	public function GetStatType() : StatViewData
	{
		return m_stat;
	}

	protected event OnButtonClick( hoverEvenet : inkPointerEvent )
	{
		var evt : CategoryClickedEvent;
		var widget : inkWidget;
		var controller : StatsViewController;
		widget = hoverEvenet.GetTarget();
		controller = ( ( StatsViewController )( widget.GetController() ) );
		evt = new CategoryClickedEvent;
		evt.statsData = controller.GetStatType();
		QueueEvent( evt );
	}

	protected event OnUninitialize()
	{
		this.UnregisterFromCallback( 'OnHoverOver', this, 'OnButtonClick' );
	}

}

class StatsDetailViewController extends inkLogicController
{
	private editable var m_StatLabelRef : inkTextRef;
	private editable var m_StatValueRef : inkTextRef;

	protected event OnInitialize()
	{
		GetRootWidget().SetVisible( false );
	}

	public function Setup( const stat : ref< StatViewData > )
	{
		inkTextRef.SetText( m_StatLabelRef, stat.statName );
		GetRootWidget().SetVisible( true );
		switch( stat.type )
		{
			case gamedataStatType.AttacksPerSecond:
			case gamedataStatType.MaxSpeed:
				inkTextRef.SetText( m_StatValueRef, FloatToStringPrec( stat.valueF, 2 ) );
			break;
			case gamedataStatType.CritChance:
			case gamedataStatType.CritDamage:
			case gamedataStatType.BonusRicochetDamage:
			case gamedataStatType.StealthHitDamageBonus:
				inkTextRef.SetText( m_StatValueRef, FloatToStringPrec( stat.valueF, 2 ) + "%" );
			break;
			case gamedataStatType.EffectiveDPS:
				inkTextRef.SetText( m_StatValueRef, FloatToStringPrec( stat.valueF - ModF( stat.valueF, 0.1 ), 1 ) );
			break;
			case gamedataStatType.MemoryRegenRate:
				inkTextRef.SetText( m_StatValueRef, FloatToStringPrec( stat.valueF * 100.0, 0 ) + "%" );
			break;
			case gamedataStatType.MitigationChance:
			case gamedataStatType.MitigationStrength:
			case gamedataStatType.HealthGeneralRegenRateMult:
			case gamedataStatType.StaminaRegenRate:
			case gamedataStatType.IntrinsicQuickHackUploadBonus:
			case gamedataStatType.ChargeMultiplier:
			case gamedataStatType.StaminaCostReduction:
			case gamedataStatType.ExplosionResistance:
			case gamedataStatType.MeleeResistance:
			case gamedataStatType.DamageReductionDamageOverTime:
			case gamedataStatType.DamageReductionQuickhacks:
			case gamedataStatType.BonusDamageAgainstElites:
			case gamedataStatType.BonusDamageAgainstRares:
			case gamedataStatType.BonusDamageAgainstBosses:
			case gamedataStatType.FallDamageReduction:
			case gamedataStatType.Visibility:
			case gamedataStatType.MeleeDamagePercentBonus:
			case gamedataStatType.HeadshotDamageMultiplier:
			case gamedataStatType.BonusQuickHackDamage:
				inkTextRef.SetText( m_StatValueRef, IntToString( stat.value ) + "%" );
			break;
			default:
				inkTextRef.SetText( m_StatValueRef, IntToString( stat.value ) );
			break;
		}
	}

}

class StatsDetailListController extends inkLogicController
{
	private editable var m_StatLabelRef : inkTextRef;
	private editable var m_statsList : inkCompoundRef;

	protected event OnInitialize()
	{
		GetRootWidget().SetVisible( false );
	}

	public function SetData( const categoryData : ref< StatViewData >, const detailsData : ref< array< StatViewData > > )
	{
		var i : Int32;
		var statViewWidget : weak< inkWidget >;
		var statView : weak< StatsDetailViewController >;
		GetRootWidget().SetVisible( true );
		inkTextRef.SetText( m_StatLabelRef, categoryData.statName );
		inkCompoundRef.RemoveAllChildren( m_statsList );
		for( i = 0; i < detailsData.Size(); i += 1 )
		{
			if( detailsData[ i ].valueF != 0.0 )
			{
				statViewWidget = SpawnFromLocal( inkCompoundRef.Get( m_statsList ), 'statDetailView' );
				statView = ( ( StatsDetailViewController )( statViewWidget.GetControllerByType( 'StatsDetailViewController' ) ) );
				statView.Setup( detailsData[ i ] );
			}
		}
	}

}

class CategoryClickedEvent extends Event
{
	var statsData : StatViewData;
}

class StatsPlayTimeController extends inkLogicController
{
	private editable var m_playTimeRef : inkTextRef;
	private editable var m_lifePathRef : inkTextRef;
	private editable var m_lifePathIconRef : inkImageRef;

	public function Set( playTime : Float, lifePath : gamedataLifePath )
	{
		var textParamsRef : inkTextParams;
		var hours, minutes : String;
		var hrs, mins : Int32;
		hrs = RoundF( ( ( Float )( playTime / 3600.0 ) ) );
		mins = RoundF( ( ( Float )( ( playTime % 3600.0 ) / 60.0 ) ) );
		textParamsRef = new inkTextParams;
		textParamsRef.AddNumber( "HOURS", hrs );
		textParamsRef.AddNumber( "MINUTES", mins );
		hours = ( ( hrs > 9 ) ? ( "{HOURS}:" ) : ( "0{HOURS}:" ) );
		minutes = ( ( mins > 9 ) ? ( "{MINUTES}" ) : ( "0{MINUTES}" ) );
		inkTextRef.SetText( m_playTimeRef, hours + minutes );
		inkTextRef.SetTextParameters( m_playTimeRef, textParamsRef );
		switch( lifePath )
		{
			case gamedataLifePath.Corporate:
				inkTextRef.SetText( m_lifePathRef, GetLocalizedText( "Gameplay-LifePaths-Corporate" ) );
			inkImageRef.SetTexturePart( m_lifePathIconRef, 'LifepathCorpo' );
			break;
			case gamedataLifePath.Nomad:
				inkTextRef.SetText( m_lifePathRef, GetLocalizedText( "Gameplay-LifePaths-Nomad" ) );
			inkImageRef.SetTexturePart( m_lifePathIconRef, 'LifepathNomad' );
			break;
			case gamedataLifePath.StreetKid:
				inkTextRef.SetText( m_lifePathRef, GetLocalizedText( "Gameplay-LifePaths-Streetkid" ) );
			inkImageRef.SetTexturePart( m_lifePathIconRef, 'LifepathStreetKid' );
			break;
		}
	}

}

class SteetCredDataHelper
{

	public static function GetData() : array< LevelRewardDisplayData >
	{
		var dataArray : array< LevelRewardDisplayData >;
		var data : LevelRewardDisplayData;
		var records : array< TweakDBID >;
		var i : Int32;
		records.PushBack( T"UIMaps.StreetCredMap_Level_5" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_10" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_15" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_20" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_25" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_30" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_35" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_40" );
		records.PushBack( T"UIMaps.StreetCredMap_Level_50" );
		for( i = 0; i < records.Size(); i += 1 )
		{
			data = new LevelRewardDisplayData;
			data.level = TweakDBInterface.GetInt( records[ i ] + T".level", 0 );
			data.description = TweakDBInterface.GetString( records[ i ] + T".desc", "" );
			data.icon = TweakDBInterface.GetCName( records[ i ] + T".icon", '' );
			dataArray.PushBack( data );
		}
		return dataArray;
	}

}

class LevelRewardDisplayData extends IDisplayData
{
	var level : Int32;
	var rewardName : String;
	var description : String;
	var icon : CName;
	var locPackage : UILocalizationDataPackage;
	var descPackage : UILocalizationDataPackage;
	var isLock : Bool;
}

