class PerkDisplayController extends inkButtonController
{
	protected editable var m_levelText : inkTextRef;
	protected editable var m_icon : inkImageRef;
	protected editable var m_fluffText : inkTextRef;
	protected editable var m_requiredTrainerIcon : inkWidgetRef;
	protected editable var m_requiredPointsText : inkTextRef;
	protected var m_displayData : BasePerkDisplayData;
	protected var m_dataManager : PlayerDevelopmentDataManager;
	protected var m_playerDevelopmentData : weak< PlayerDevelopmentData >;
	protected var m_recentlyPurchased : Bool;
	protected var m_holdStarted : Bool;
	protected var m_isTrait : Bool;
	protected var m_wasLocked : Bool;
	protected var m_index : Int32;
	protected var m_cool_in_proxy : inkAnimProxy;
	protected var m_cool_out_proxy : inkAnimProxy;

	protected event OnInitialize()
	{
		RegisterToCallback( 'OnRelease', this, 'OnPerkDisplayClick' );
		RegisterToCallback( 'OnHold', this, 'OnPerkDisplayHold' );
		RegisterToCallback( 'OnHoverOver', this, 'OnPerkItemHoverOver' );
		RegisterToCallback( 'OnHoverOut', this, 'OnPerkItemHoverOut' );
	}

	protected event OnUninitialize()
	{
		UnregisterFromCallback( 'OnRelease', this, 'OnPerkDisplayClick' );
		UnregisterFromCallback( 'OnHold', this, 'OnPerkDisplayHold' );
		UnregisterFromCallback( 'OnHoverOver', this, 'OnPerkItemHoverOver' );
		UnregisterFromCallback( 'OnHoverOut', this, 'OnPerkItemHoverOut' );
	}

	public function Setup( displayData : BasePerkDisplayData, dataManager : PlayerDevelopmentDataManager, optional index : Int32 )
	{
		m_playerDevelopmentData = dataManager.GetPlayerDevelopmentData();
		m_index = index;
		m_isTrait = ( ( TraitDisplayData )( displayData ) ) != NULL;
		m_dataManager = dataManager;
		UpdateLayout( displayData );
		CheckRevealAnimation( displayData, m_displayData );
		m_displayData = displayData;
	}

	public function CheckRevealAnimation( newDisplayData : BasePerkDisplayData, oldDisplayData : BasePerkDisplayData )
	{
		var isFirstTime : Bool;
		var unlimitedUnlocked : UnlimitedUnlocked;
		if( oldDisplayData )
		{
			isFirstTime = oldDisplayData.m_proficiency != newDisplayData.m_proficiency;
		}
		else
		{
			isFirstTime = true;
		}
		if( isFirstTime )
		{
			m_wasLocked = newDisplayData.m_locked;
		}
		else
		{
			m_wasLocked = oldDisplayData.m_locked;
			if( m_wasLocked && !( newDisplayData.m_locked ) )
			{
				if( m_isTrait )
				{
					unlimitedUnlocked = new UnlimitedUnlocked;
					QueueEvent( unlimitedUnlocked );
				}
				else
				{
					PlayLibraryAnimation( 'reveal_perk' );
				}
			}
		}
	}

	private function UpdateLayout( data : BasePerkDisplayData )
	{
		var state : CName;
		var root : weak< inkWidget >;
		var isDataNull : Bool;
		root = GetRootWidget();
		isDataNull = data == NULL;
		if( isDataNull == root.IsVisible() )
		{
			root.SetVisible( !( isDataNull ) );
		}
		if( isDataNull )
		{
			return;
		}
		state = 'Default';
		if( data.m_locked )
		{
			state = 'Locked';
		}
		else if( data.m_level == data.m_maxLevel )
		{
			state = 'Maxed';
		}
		else if( data.m_level > 0 )
		{
			state = 'Bought';
		}
		GetRootWidget().SetState( state );
		InkImageUtils.RequestSetImage( this, m_icon, data.m_iconID );
		inkImageRef.SetVisible( m_icon, TDBID.IsValid( data.m_iconID ) );
		if( !( m_isTrait ) )
		{
			UpdateLayout( ( ( PerkDisplayData )( data ) ) );
		}
		else
		{
			UpdateLayout( ( ( TraitDisplayData )( data ) ) );
		}
	}

	private function UpdateLayout( data : PerkDisplayData )
	{
		var perkAreaRecord : PerkArea_Record;
		var numPointsRequired : Int32;
		var requiresPoints : Bool;
		var requiresMastery : Bool;
		var levelParams : inkTextParams;
		var statPrereqRecord : StatPrereq_Record;
		var statType : gamedataStatType;
		var statValue : Float;
		numPointsRequired = 0;
		requiresPoints = false;
		requiresMastery = false;
		levelParams = new inkTextParams;
		perkAreaRecord = m_playerDevelopmentData.GetPerkAreaRecord( data.m_area );
		statPrereqRecord = ( ( StatPrereq_Record )( perkAreaRecord.Requirement() ) );
		statType = ( ( gamedataStatType )( ( ( Int32 )( EnumValueFromName( 'gamedataStatType', statPrereqRecord.StatType() ) ) ) ) );
		statValue = GameInstance.GetStatsSystem( m_dataManager.GetPlayer().GetGame() ).GetStatValue( m_dataManager.GetPlayer().GetEntityID(), statType );
		numPointsRequired = ( ( Int32 )( statPrereqRecord.ValueToCheck() ) ) - ( ( Int32 )( statValue ) );
		requiresPoints = numPointsRequired > 0;
		inkTextRef.SetVisible( m_requiredPointsText, requiresPoints );
		inkTextRef.SetText( m_requiredPointsText, IntToString( numPointsRequired ) );
		requiresMastery = !( m_playerDevelopmentData.IsPerkAreaMasteryReqMet( perkAreaRecord ) );
		inkWidgetRef.SetVisible( m_requiredTrainerIcon, requiresMastery );
		levelParams.AddString( "level", IntToString( data.m_level ) );
		levelParams.AddString( "maxLevel", IntToString( data.m_maxLevel ) );
		inkTextRef.SetTextParameters( m_levelText, levelParams );
		inkTextRef.SetText( m_fluffText, ( ( "FNC_" + IntToString( GetFluffRand( data ) ) ) + " " ) + IntToString( GetFluffRand( data, 3425 ) ) );
	}

	private function UpdateLayout( data : TraitDisplayData )
	{
		var traitRecord : Trait_Record;
		var numPointsRequired : Int32;
		var requiresPoints : Bool;
		var levelParams : inkTextParams;
		var statPrereqRecord : StatPrereq_Record;
		var prereq : StatPrereq_Record;
		var proficiencyType : gamedataProficiencyType;
		numPointsRequired = 0;
		requiresPoints = false;
		levelParams = new inkTextParams;
		prereq = ( ( StatPrereq_Record )( traitRecord.Requirement() ) );
		proficiencyType = ( ( gamedataProficiencyType )( ( ( Int32 )( EnumValueFromName( 'gamedataProficiencyType', statPrereqRecord.StatType() ) ) ) ) );
		numPointsRequired = ( ( Int32 )( prereq.ValueToCheck() ) ) - m_playerDevelopmentData.GetProficiencyLevel( proficiencyType );
		traitRecord = RPGManager.GetTraitRecord( data.m_type );
		requiresPoints = numPointsRequired > 0;
		inkTextRef.SetVisible( m_requiredPointsText, requiresPoints );
		inkTextRef.SetText( m_requiredPointsText, IntToString( numPointsRequired ) );
		levelParams.AddString( "level", IntToString( data.m_level ) );
		inkTextRef.SetTextParameters( m_levelText, levelParams );
		inkTextRef.SetText( m_fluffText, ( ( "FNC_" + IntToString( GetFluffRand( data ) ) ) + " " ) + IntToString( GetFluffRand( data, 6327 ) ) );
	}

	protected function GetFluffRand( perkData : PerkDisplayData, optional offset : Int32 ) : Int32
	{
		return ( ( Int32 )( RandNoiseF( ( ( ( ( ( Int32 )( perkData.m_proficiency ) ) * 1000 ) + ( ( ( Int32 )( perkData.m_area ) ) * 100 ) ) + ( ( Int32 )( perkData.m_type ) ) ) + offset, 1000.0, 9999.0 ) ) );
	}

	protected function GetFluffRand( traitData : TraitDisplayData, optional offset : Int32 ) : Int32
	{
		return ( ( Int32 )( RandNoiseF( ( ( ( ( Int32 )( traitData.m_level ) ) * 100 ) + ( ( Int32 )( traitData.m_type ) ) ) + offset, 1000.0, 9999.0 ) ) );
	}

	private function Upgrade()
	{
		if( !( m_isTrait ) )
		{
			m_dataManager.UpgradePerk( ( ( PerkDisplayData )( m_displayData ) ) );
		}
		else
		{
			m_dataManager.UpgradeTrait( ( ( TraitDisplayData )( m_displayData ) ) );
		}
	}

	protected event OnUnlimitedUnlocked( evt : UnlimitedUnlocked )
	{
		if( m_isTrait )
		{
			PlayLibraryAnimation( 'reveal_unlimited_perk' );
		}
	}

	protected event OnPerkItemHoverOver( evt : inkPointerEvent )
	{
		var hoverOverEvent : PerkHoverOverEvent;
		hoverOverEvent = new PerkHoverOverEvent;
		hoverOverEvent.widget = GetRootWidget();
		hoverOverEvent.perkIndex = m_index;
		hoverOverEvent.perkData = m_displayData;
		QueueEvent( hoverOverEvent );
		StopHoverAnimations();
		m_cool_in_proxy = PlayLibraryAnimation( ( ( m_isTrait ) ? ( 'cool_unlimited_hover' ) : ( 'cool_hover' ) ) );
	}

	protected event OnPerkItemHoverOut( evt : inkPointerEvent )
	{
		var hoverOutEvent : PerkHoverOutEvent;
		hoverOutEvent = new PerkHoverOutEvent;
		hoverOutEvent.widget = GetRootWidget();
		hoverOutEvent.perkData = m_displayData;
		QueueEvent( hoverOutEvent );
		StopHoverAnimations();
		m_cool_out_proxy = PlayLibraryAnimation( ( ( m_isTrait ) ? ( 'cool_unlimited_hover_out' ) : ( 'cool_hover_out' ) ) );
	}

	private function StopHoverAnimations()
	{
		if( m_cool_in_proxy )
		{
			m_cool_in_proxy.Stop();
		}
		if( m_cool_out_proxy )
		{
			m_cool_out_proxy.Stop();
		}
	}

	protected event OnPerkDisplayClick( evt : inkPointerEvent )
	{
		m_holdStarted = false;
	}

	protected event OnPerkDisplayHold( evt : inkPointerEvent )
	{
		var progress : Float;
		var holdStartEvent : PerksItemHoldStart;
		if( evt.IsAction( 'upgrade_perk' ) )
		{
			progress = evt.GetHoldProgress();
			if( ( progress > 0.0 ) && !( m_holdStarted ) )
			{
				holdStartEvent = new PerksItemHoldStart;
				holdStartEvent.widget = GetRootWidget();
				holdStartEvent.perkData = m_displayData;
				holdStartEvent.actionName = evt.GetActionName();
				QueueEvent( holdStartEvent );
				m_holdStarted = true;
				if( !( m_dataManager.IsPerkUpgradeable( m_displayData, true ) ) && IsActionNameCompatible( evt ) )
				{
					PlayLibraryAnimation( ( ( m_isTrait ) ? ( 'locked_unlimited_perk' ) : ( 'locked_perk' ) ) );
					PlaySound( 'Perk', 'OnBuyFail' );
				}
			}
			if( progress >= 1.0 )
			{
				if( m_dataManager.IsPerkUpgradeable( m_displayData ) && IsActionNameCompatible( evt ) )
				{
					m_recentlyPurchased = true;
					Upgrade();
					if( m_displayData.m_level == ( m_displayData.m_maxLevel - 1 ) )
					{
						PlayLibraryAnimation( 'maxed_perk' );
						PlaySound( 'Perk', 'OnBuyFail' );
					}
					else if( m_displayData.m_level >= 0 )
					{
						PlayLibraryAnimation( ( ( m_isTrait ) ? ( 'buy_unlimited_perk' ) : ( 'buy_perk' ) ) );
						PlaySound( 'Perk', 'OnLevelUp' );
					}
				}
			}
			else
			{
				if( !( m_recentlyPurchased ) )
				{
					m_recentlyPurchased = false;
				}
			}
		}
	}

	private function IsActionNameCompatible( evt : inkPointerEvent ) : Bool
	{
		return ( evt.IsAction( 'use_item' ) || evt.IsAction( 'click' ) ) || evt.IsAction( 'upgrade_perk' );
	}

}

class PerkDisplayContainerController extends inkLogicController
{
	protected editable var m_index : Int32;
	protected editable var m_isTrait : Bool;
	protected editable var m_widget : inkWidgetRef;
	protected var m_data : BasePerkDisplayData;
	protected var m_dataManager : PlayerDevelopmentDataManager;
	protected var m_controller : weak< PerkDisplayController >;

	protected event OnInitialize()
	{
		var evt : PerkDisplayContainerCreatedEvent;
		evt = new PerkDisplayContainerCreatedEvent;
		evt.index = m_index;
		evt.isTrait = m_isTrait;
		evt.container = this;
		QueueEvent( evt );
	}

	private function SpawnController()
	{
		var widget : weak< inkWidget >;
		( ( weak< weak< inkCompoundWidget > > )( GetRootWidget() ) ).RemoveAllChildren();
		widget = SpawnFromLocal( ( ( weak< weak< inkCompoundWidget > > )( GetRootWidget() ) ), ( ( m_isTrait ) ? ( 'SkillUnlimitedPerkDisplay' ) : ( 'SkillPerkDisplay' ) ) );
		widget.SetVAlign( inkEVerticalAlign.Top );
		widget.SetHAlign( inkEHorizontalAlign.Left );
		m_controller = ( ( PerkDisplayController )( widget.GetController() ) );
	}

	public function SetData( perkData : BasePerkDisplayData, dataManager : PlayerDevelopmentDataManager )
	{
		m_data = perkData;
		m_dataManager = dataManager;
		if( m_controller == NULL )
		{
			SpawnController();
		}
		m_controller.Setup( m_data, m_dataManager, m_index );
	}

	public function GetPerkDisplayData() : BasePerkDisplayData
	{
		return m_data;
	}

	public function GetPerkIndex() : Int32
	{
		return m_index;
	}

}

class UnlimitedUnlocked extends Event
{
}

