class activityLogGameController extends inkHUDGameController
{
	private var m_readIndex : Int32;
	private var m_writeIndex : Int32;
	private var m_maxSize : Int32;
	private var m_entries : array< String >;
	private editable var m_panel : inkVerticalPanelRef;
	private var m_onNewEntries : CallbackHandle;
	private var m_onHide : CallbackHandle;

	protected event OnInitialize()
	{
		var i, count : Int32;
		var entry : weak< activityLogEntryLogicController >;
		var uiBlackboard : IBlackboard;
		var bb : IBlackboard;
		m_readIndex = 0;
		m_writeIndex = 0;
		m_maxSize = 20;
		m_entries.Resize( m_maxSize );
		if( inkVerticalPanelRef.Get( m_panel ) )
		{
			count = inkVerticalPanelRef.GetNumChildren( m_panel );
			for( i = 0; i < count; i += 1 )
			{
				entry = ( ( activityLogEntryLogicController )( inkVerticalPanelRef.GetWidget( m_panel, i ).GetController() ) );
				if( entry )
				{
					entry.Reset();
					entry.RegisterToCallback( 'OnTypingFinished', this, 'OnTypingFinished' );
					entry.RegisterToCallback( 'OnDisappeared', this, 'OnDisappeared' );
				}
			}
		}
		uiBlackboard = GetUIBlackboard();
		if( uiBlackboard )
		{
			m_onNewEntries = uiBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UIGameData.ActivityLog, this, 'OnNewEntries' );
		}
		bb = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_ActivityLog );
		if( bb )
		{
			m_onHide = bb.RegisterListenerBool( GetAllBlackboardDefs().UI_ActivityLog.activityLogHide, this, 'OnHide' );
		}
	}

	protected event OnUninitialize()
	{
		var uiBlackboard : IBlackboard;
		var bb : IBlackboard;
		uiBlackboard = GetUIBlackboard();
		if( uiBlackboard )
		{
			uiBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UIGameData.ActivityLog, m_onNewEntries );
		}
		bb = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_ActivityLog );
		if( bb )
		{
			bb.UnregisterListenerBool( GetAllBlackboardDefs().UI_ActivityLog.activityLogHide, m_onHide );
		}
	}

	public function AddNewEntry( const value : ref< String > )
	{
		var bReset : Bool;
		var i, count : Int32;
		var widget : weak< inkWidget >;
		var entry : weak< activityLogEntryLogicController >;
		count = inkVerticalPanelRef.GetNumChildren( m_panel );
		bReset = true;
		for( i = 0; i < count; i += 1 )
		{
			widget = inkVerticalPanelRef.GetWidget( m_panel, i );
			entry = ( ( activityLogEntryLogicController )( widget.GetController() ) );
			if( entry.IsAvailable() )
			{
				entry.SetText( value );
				bReset = false;
				break;
			}
		}
		if( bReset )
		{
			widget = inkVerticalPanelRef.GetWidget( m_panel, 0 );
			entry = ( ( activityLogEntryLogicController )( widget.GetController() ) );
			entry.Reset();
			entry.SetText( value );
			inkVerticalPanelRef.ReorderChild( m_panel, widget, -1 );
		}
	}

	protected event OnNewEntries( value : Variant )
	{
		var bAdd : Bool;
		var i, count : Int32;
		var newEntries : array< String >;
		newEntries = ( ( array< String > )value );
		bAdd = m_readIndex == m_writeIndex;
		count = newEntries.Size();
		for( i = 0; i < count; i += 1 )
		{
			if( ( m_writeIndex - m_readIndex ) < m_maxSize )
			{
				m_entries[ m_writeIndex % m_maxSize ] = newEntries[ i ];
				m_writeIndex += 1;
			}
			else
			{
				break;
			}
		}
		if( bAdd && ( m_readIndex < m_writeIndex ) )
		{
			AddNewEntry( m_entries[ m_readIndex ] );
		}
	}

	protected event OnTypingFinished( widget : weak< inkWidget > )
	{
		m_entries[ m_readIndex % m_maxSize ] = "";
		m_readIndex += 1;
		if( m_readIndex < m_writeIndex )
		{
			AddNewEntry( m_entries[ m_readIndex % m_maxSize ] );
		}
		else
		{
			m_readIndex = 0;
			m_writeIndex = 0;
		}
	}

	protected event OnDisappeared( widget : weak< inkWidget > )
	{
		var entry : weak< activityLogEntryLogicController >;
		entry = ( ( activityLogEntryLogicController )( widget.GetController() ) );
		entry.Reset();
		inkVerticalPanelRef.ReorderChild( m_panel, widget, -1 );
	}

	protected event OnHide( val : Bool )
	{
		inkVerticalPanelRef.SetVisible( m_panel, !( val ) );
	}

}

class activityLogEntryLogicController extends inkLogicController
{
	private var m_available : Bool;
	private var m_originalSize : Uint16;
	private var m_size : Uint16;
	private var m_displayText : String;
	private var m_root : weak< inkText >;
	private var m_appearingAnim : inkAnimController;
	private var m_typingAnim : inkAnimController;
	private var m_disappearingAnim : inkAnimController;
	private var m_typingAnimDef : inkAnimDef;
	private var m_typingAnimProxy : inkAnimProxy;
	private var m_disappearingAnimDef : inkAnimDef;
	private var m_disappearingAnimProxy : inkAnimProxy;

	protected event OnInitialize()
	{
		var size : Vector2;
		m_available = true;
		m_root = ( ( inkText )( GetRootWidget() ) );
		m_root.SetLetterCase( textLetterCase.UpperCase );
		size = m_root.GetSize();
		m_appearingAnim = new inkAnimController;
		m_appearingAnim.Select( m_root ).Interpolate( 'size', Vector2( 0.0, 0.0 ), size ).Duration( 0.2 ).Type( inkanimInterpolationType.Linear ).Mode( inkanimInterpolationMode.EasyIn );
		m_typingAnim = new inkAnimController;
		m_typingAnim.Select( m_root ).Interpolate( 'transparency', 1.0, 1.0 ).Duration( 0.0005 ).Type( inkanimInterpolationType.Linear ).Mode( inkanimInterpolationMode.EasyIn );
		m_disappearingAnim = new inkAnimController;
		m_disappearingAnim.Select( m_root ).Interpolate( 'transparency', 1.0, 0.0 ).Delay( 1.0 ).Duration( 0.5 ).Type( inkanimInterpolationType.Linear ).Mode( inkanimInterpolationMode.EasyOut );
	}

	public function SetText( const displayText : ref< String > )
	{
		var typingAnimPlaybackOptions : inkAnimOptions;
		m_available = false;
		m_displayText = displayText;
		m_originalSize = ( ( Uint16 )( StrLen( m_displayText ) ) );
		m_size = m_originalSize;
		m_root.SetText( "" );
		m_appearingAnim.Stop();
		m_appearingAnim.Play();
		typingAnimPlaybackOptions.loopType = inkanimLoopType.Cycle;
		typingAnimPlaybackOptions.loopCounter = m_originalSize + 1;
		m_typingAnim.Stop();
		m_typingAnim.PlayWithOptions( typingAnimPlaybackOptions );
		m_typingAnim.RegisterToCallback( inkanimEventType.OnStartLoop, this, 'OnTyping' );
		m_typingAnim.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnStopTyping' );
		m_disappearingAnim.Stop();
	}

	public function Reset()
	{
		m_appearingAnim.Stop();
		m_typingAnim.Stop();
		m_disappearingAnim.Stop();
		m_root.SetText( "" );
		m_root.SetSize( Vector2( 0.0, 0.0 ) );
		m_available = true;
	}

	public function IsAvailable() : Bool
	{
		return m_available;
	}

	protected event OnTyping( proxy : inkAnimProxy )
	{
		var nextSymbol : String;
		nextSymbol = StrMid( m_displayText, ( ( Int32 )( m_originalSize - m_size ) ), 1 );
		m_root.SetLetterCase( textLetterCase.UpperCase );
		m_root.SetText( m_root.GetText() + nextSymbol );
		m_size -= 1;
	}

	protected event OnStopTyping( proxy : inkAnimProxy )
	{
		CallCustomCallback( 'OnTypingFinished' );
		m_disappearingAnim.Play();
		m_disappearingAnim.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnDisappeared' );
	}

	protected event OnDisappeared( proxy : inkAnimProxy )
	{
		CallCustomCallback( 'OnDisappeared' );
	}

}

