class buffListGameController extends inkHUDGameController
{
	private editable var m_buffsList : inkHorizontalPanelRef;
	private var m_bbBuffList : CallbackHandle;
	private var m_bbDeBuffList : CallbackHandle;
	private var m_uiBlackboard : weak< IBlackboard >;
	private var m_buffDataList : array< BuffInfo >;
	private var m_debuffDataList : array< BuffInfo >;
	private var m_buffWidgets : array< weak< inkWidget > >;
	private var m_UISystem : weak< UISystem >;
	private var m_pendingRequests : Int32;

	protected event OnInitialize()
	{
		m_uiBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_PlayerBioMonitor );
		if( m_uiBlackboard )
		{
			m_bbBuffList = m_uiBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.BuffsList, this, 'OnBuffDataChanged' );
			m_bbDeBuffList = m_uiBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.DebuffsList, this, 'OnDeBuffDataChanged' );
			m_uiBlackboard.SignalVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.BuffsList );
			m_uiBlackboard.SignalVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.DebuffsList );
		}
		inkHorizontalPanelRef.SetVisible( m_buffsList, false );
	}

	protected event OnUninitialize()
	{
		if( m_uiBlackboard )
		{
			m_uiBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.BuffsList, m_bbBuffList );
			m_uiBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_PlayerBioMonitor.DebuffsList, m_bbDeBuffList );
		}
	}

	protected event OnPlayerAttach( playerGameObject : GameObject )
	{
		m_UISystem = GameInstance.GetUISystem( playerGameObject.GetGame() );
	}

	protected event OnBuffDataChanged( value : Variant )
	{
		m_buffDataList = ( ( array< BuffInfo > )value );
		UpdateBuffs();
	}

	protected event OnDeBuffDataChanged( value : Variant )
	{
		m_debuffDataList = ( ( array< BuffInfo > )value );
		MergeKnockdowns();
		UpdateBuffs();
	}

	private function UpdateBuffs()
	{
		var currentBuffsAndRequests : Int32;
		var incomingBuffsCount : Int32;
		var i : Int32;
		var requestsToSpawn : Int32;
		incomingBuffsCount = m_debuffDataList.Size() + m_buffDataList.Size();
		currentBuffsAndRequests = inkHorizontalPanelRef.GetNumChildren( m_buffsList ) + m_pendingRequests;
		if( currentBuffsAndRequests < incomingBuffsCount )
		{
			m_pendingRequests = incomingBuffsCount - currentBuffsAndRequests;
			requestsToSpawn = m_pendingRequests;
			for( i = 0; i < requestsToSpawn; i = i + 1 )
			{
				AsyncSpawnFromLocal( inkHorizontalPanelRef.Get( m_buffsList ), 'Buff', this, 'OnBuffSpawned' );
			}
		}
		if( m_pendingRequests <= 0 )
		{
			UpdateBuffDebuffList();
			UpdateVisibility();
		}
	}

	private function MergeKnockdowns()
	{
		var i : Int32;
		var biggestTimeRemaining : Float;
		var toRemain : Int32;
		var toRemove : array< Int32 >;
		var effectType : gamedataStatusEffectType;
		biggestTimeRemaining = 0.0;
		for( i = 0; i < m_debuffDataList.Size(); i = i + 1 )
		{
			effectType = TDB.GetStatusEffectRecord( m_debuffDataList[ i ].buffID ).StatusEffectType().Type();
			if( effectType == gamedataStatusEffectType.Knockdown || effectType == gamedataStatusEffectType.VehicleKnockdown )
			{
				if( biggestTimeRemaining > 0.0 )
				{
					toRemove.PushBack( i );
				}
				else
				{
					toRemain = i;
				}
				biggestTimeRemaining = MaxF( biggestTimeRemaining, m_debuffDataList[ i ].timeRemaining );
			}
		}
		if( toRemove.Size() == 0 )
		{
			return;
		}
		for( i = 0; i < toRemove.Size(); i = i + 1 )
		{
			m_debuffDataList.Erase( toRemove[ i ] - i );
		}
		m_debuffDataList[ toRemain ].timeRemaining = biggestTimeRemaining;
	}

	protected event OnBuffSpawned( newItem : inkWidget, userData : IScriptable )
	{
		newItem.SetVisible( false );
		m_buffWidgets.PushBack( newItem );
		m_pendingRequests -= 1;
		if( m_pendingRequests <= 0 )
		{
			UpdateBuffDebuffList();
			UpdateVisibility();
		}
	}

	private function UpdateVisibility()
	{
		GetRootWidget().SetVisible( false );
		GetRootWidget().SetVisible( true );
		GetRootWidget().SetVisible( inkHorizontalPanelRef.IsVisible( m_buffsList ) );
	}

	private function UpdateBuffDebuffList()
	{
		var data : StatusEffect_Record;
		var buffList : array< BuffInfo >;
		var onScreenBuffsCount : Int32;
		var incomingBuffsCount : Int32;
		var visibleIncomingBuffsCount : Int32;
		var i : Int32;
		var currBuffWidget : weak< inkWidget >;
		var currBuffLoc : weak< buffListItemLogicController >;
		var buffTimeRemaining : Float;
		var buffTimeTotal : Float;
		for( i = 0; i < m_buffDataList.Size(); i = i + 1 )
		{
			buffList.PushBack( m_buffDataList[ i ] );
		}
		for( i = 0; i < m_debuffDataList.Size(); i = i + 1 )
		{
			buffList.PushBack( m_debuffDataList[ i ] );
		}
		incomingBuffsCount = buffList.Size();
		onScreenBuffsCount = inkHorizontalPanelRef.GetNumChildren( m_buffsList );
		for( i = 0; i < onScreenBuffsCount; i = i + 1 )
		{
			currBuffWidget = m_buffWidgets[ i ];
			currBuffLoc = ( ( buffListItemLogicController )( currBuffWidget.GetController() ) );
			if( i >= incomingBuffsCount )
			{
				currBuffWidget.SetVisible( false );
				currBuffLoc.SetStatusEffectRecord( NULL );
				continue;
			}
			data = TDB.GetStatusEffectRecord( buffList[ i ].buffID );
			buffTimeRemaining = buffList[ i ].timeRemaining;
			buffTimeTotal = buffList[ i ].timeTotal;
			if( ( !( data ) || !( data.UiData() ) ) || data.UiData().IconPath() == "" )
			{
				currBuffWidget.SetVisible( false );
				currBuffLoc.SetStatusEffectRecord( NULL );
				continue;
			}
			if( data != currBuffLoc.GetStatusEffectRecord() )
			{
				currBuffLoc.SetStatusEffectRecord( data );
				currBuffLoc.PlayLibraryAnimation( 'intro' );
			}
			currBuffLoc.SetData( StringToName( data.UiData().IconPath() ), buffTimeRemaining, buffTimeTotal, ( ( Int32 )( buffList[ i ].stackCount ) ) );
			currBuffWidget.SetVisible( true );
			visibleIncomingBuffsCount += 1;
		}
		SendVisibilityUpdate( inkHorizontalPanelRef.IsVisible( m_buffsList ), visibleIncomingBuffsCount > 0 );
		inkHorizontalPanelRef.SetVisible( m_buffsList, visibleIncomingBuffsCount > 0 );
	}

	private function SendVisibilityUpdate( oldVisible : Bool, nowVisible : Bool )
	{
		var evt : BuffListVisibilityChangedEvent;
		if( oldVisible != nowVisible )
		{
			evt = new BuffListVisibilityChangedEvent;
			evt.m_hasBuffs = nowVisible;
			m_UISystem.QueueEvent( evt );
		}
	}

}

class buffListItemLogicController extends inkLogicController
{
	private editable var m_icon : inkImageRef;
	private editable var m_iconBg : inkImageRef;
	private editable var m_fill : inkWidgetRef;
	private var m_fillWidget : weak< inkWidget >;
	private editable var m_timeLabel : inkTextRef;
	private editable var m_stackCounter : inkTextRef;
	private editable var m_stackCounterContainer : inkWidgetRef;
	private editable var m_statusEffectRecord : weak< StatusEffect_Record >;

	protected event OnInitialize()
	{
		m_fillWidget = inkWidgetRef.Get( m_fill );
	}

	public function SetData( icon : CName, time : Float, totalTime : Float, optional stackCount : Int32 )
	{
		if( stackCount > 1 )
		{
			inkWidgetRef.SetVisible( m_stackCounterContainer, true );
			inkTextRef.SetText( m_stackCounter, "x" + IntToString( stackCount ) );
		}
		else
		{
			inkWidgetRef.SetVisible( m_stackCounterContainer, false );
		}
		SetTimeFill( time, totalTime );
		SetTimeText( time );
		InkImageUtils.RequestSetImage( this, m_icon, "UIIcon." + NameToString( icon ) );
		InkImageUtils.RequestSetImage( this, m_iconBg, "UIIcon." + NameToString( icon ) );
	}

	private function SetTimeFill( time : Float, totalTime : Float )
	{
		m_fillWidget.SetEffectParamValue( inkEffectType.RadialWipe, 'RadialWipe', 'transition', time / totalTime );
	}

	private function SetTimeText( f : Float )
	{
		var textParams : inkTextParams;
		var time : GameTime;
		var minutes : Int32;
		var seconds : Int32;
		textParams = new inkTextParams;
		time = GameTime.MakeGameTime( 0, 0, 0, ( ( Int32 )( f ) ) );
		minutes = GameTime.Minutes( time );
		seconds = GameTime.Seconds( time );
		if( f >= 0.0 )
		{
			inkTextRef.SetVisible( m_timeLabel, true );
			if( minutes > 0 )
			{
				inkTextRef.SetText( m_timeLabel, "{TIME,time,mm:ss}" );
				textParams.AddTime( "TIME", time );
				inkTextRef.SetTextParameters( m_timeLabel, textParams );
			}
			else
			{
				inkTextRef.SetText( m_timeLabel, ( ( String )( seconds ) ) );
			}
		}
		else
		{
			inkTextRef.SetVisible( m_timeLabel, false );
		}
	}

	public function SetData( icon : TweakDBID, time : Float, totalTime : Float )
	{
		SetTimeText( time );
		SetTimeFill( time, totalTime );
		InkImageUtils.RequestSetImage( this, m_icon, icon );
		InkImageUtils.RequestSetImage( this, m_iconBg, icon );
	}

	public function SetData( icon : CName, stackCount : Int32 )
	{
		if( stackCount > 1 )
		{
			inkWidgetRef.SetVisible( m_stackCounterContainer, true );
			inkTextRef.SetText( m_stackCounter, "x" + ( ( String )( stackCount ) ) );
		}
		else
		{
			inkWidgetRef.SetVisible( m_stackCounterContainer, false );
		}
		InkImageUtils.RequestSetImage( this, m_icon, "UIIcon." + NameToString( icon ) );
		InkImageUtils.RequestSetImage( this, m_iconBg, "UIIcon." + NameToString( icon ) );
	}

	public function GetStatusEffectRecord() : StatusEffect_Record
	{
		return m_statusEffectRecord;
	}

	public function SetStatusEffectRecord( record : weak< StatusEffect_Record > )
	{
		m_statusEffectRecord = record;
	}

}

class BuffListVisibilityChangedEvent extends Event
{
	var m_hasBuffs : Bool;
}

