class QuickhackDescriptionUpdate extends Event
{
}

class QuickhacksListItemController extends ListItemController
{
	private var m_expandAnimationDuration : Float;
	default m_expandAnimationDuration = 0.2f;
	private editable var m_icon : inkImageRef;
	private editable var m_description : inkTextRef;
	private editable var m_memoryValue : inkTextRef;
	private editable var m_memoryCells : inkCompoundRef;
	private editable var m_actionStateRoot : inkWidgetRef;
	private editable var m_actionStateText : inkTextRef;
	private editable var m_categoryRoot : inkWidgetRef;
	private editable var m_categoryText : inkTextRef;
	private editable var m_revealRoot : inkWidgetRef;
	private editable var m_revealText : inkTextRef;
	private editable var m_cooldownIcon : inkWidgetRef;
	private editable var m_cooldownValue : inkTextRef;
	private editable var m_descriptionSize : inkWidgetRef;
	private editable var m_costReductionArrow : inkImageRef;
	private editable var m_curveRadius : Float;
	private editable var m_categorizedHacks : Bool;
	default m_categorizedHacks = false;
	private editable var m_colorCodedHacks : Bool;
	default m_colorCodedHacks = false;
	private editable var m_hackColorDamage : CName;
	default m_hackColorDamage = 'QuickHackAction.iconColorDamage';
	private editable var m_hackColorControl : CName;
	default m_hackColorControl = 'QuickHackAction.iconColorControl';
	private editable var m_hackColorCovert : CName;
	default m_hackColorCovert = 'QuickHackAction.iconColorCovert';
	private editable var m_hackColorUltimate : CName;
	default m_hackColorUltimate = 'QuickHackAction.iconColorUltimate';
	private editable var m_hackColorDefault : CName;
	default m_hackColorDefault = 'QuickHackAction.textColor';
	private var m_selectedLoop : inkAnimProxy;
	private var m_currentAnimationName : CName;
	private var m_choiceAccepted : inkAnimProxy;
	private var m_resizeAnim : inkAnimController;
	private var m_root : weak< inkWidget >;
	private var m_data : QuickhackData;
	private var m_isSelected : Bool;
	private var m_expanded : Bool;
	private var m_cachedDescriptionSize : Vector2;
	private var m_defaultMargin : inkMargin;

	protected event OnInitialize()
	{
		m_root = GetRootWidget();
		RegisterToCallback( 'OnSelected', this, 'OnSelected' );
		RegisterToCallback( 'OnDeselected', this, 'OnDeselected' );
		inkTextRef.SetVisible( m_description, false );
		AdjustToTextDescriptionSize( true );
	}

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

	protected event OnDataChanged( value : IScriptable )
	{
		var hackCategory : HackCategory_Record;
		var hackColor : CName;
		var textParams : inkTextParams;
		var currText : String;
		hackColor = m_hackColorDefault;
		m_currentAnimationName = '';
		m_data = ( ( QuickhackData )( value ) );
		hackCategory = m_data.m_category;
		if( m_colorCodedHacks && hackCategory )
		{
			if( hackCategory.Type() == gamedataHackCategory.DamageHack )
			{
				hackColor = m_hackColorDamage;
			}
			else if( hackCategory.Type() == gamedataHackCategory.ControlHack )
			{
				hackColor = m_hackColorControl;
			}
			else if( hackCategory.Type() == gamedataHackCategory.CovertHack )
			{
				hackColor = m_hackColorCovert;
			}
			else if( hackCategory.Type() == gamedataHackCategory.UltimateHack )
			{
				hackColor = m_hackColorUltimate;
			}
		}
		if( TDBID.IsValid( m_data.m_icon ) )
		{
			InkImageUtils.RequestSetImage( this, m_icon, m_data.m_icon );
			if( m_colorCodedHacks )
			{
				inkImageRef.Get( m_icon ).BindProperty( 'tintColor', hackColor );
			}
		}
		m_selectedLoop.UnregisterFromAllCallbacks( inkanimEventType.OnFinish );
		inkTextRef.SetText( m_labelPathRef, m_data.m_title );
		if( m_categorizedHacks && hackCategory )
		{
			inkWidgetRef.SetVisible( m_categoryRoot, true );
			inkTextRef.SetLocalizedTextScript( m_categoryText, hackCategory.LocalizedDescription() );
			if( m_colorCodedHacks )
			{
				inkTextRef.Get( m_categoryText ).BindProperty( 'tintColor', hackColor );
			}
		}
		else
		{
			inkWidgetRef.SetVisible( m_categoryRoot, false );
		}
		if( m_data && IsStringValid( m_data.m_titleAlternative ) )
		{
			inkTextRef.SetText( m_labelPathRef, m_data.m_titleAlternative );
		}
		else
		{
			inkTextRef.SetText( m_labelPathRef, m_data.m_title );
		}
		inkWidgetRef.SetVisible( m_revealRoot, m_data.m_willReveal || m_data.m_showRevealInfo );
		if( m_data.m_willReveal )
		{
			inkTextRef.SetLocalizedTextString( m_revealText, "LocKey#92125" );
		}
		else if( m_data.m_showRevealInfo )
		{
			currText = GetLocalizedText( "LocKey#92126" );
			if( m_data.m_awarenessCost < 0.0 )
			{
				currText = StrReplace( currText, "+", "" );
			}
			textParams = new inkTextParams;
			textParams.AddNumber( "float_0", m_data.m_awarenessCost );
			inkTextRef.SetText( m_revealText, currText, textParams );
		}
		SetCooldownVisibility( false );
		SetActionState();
		inkTextRef.SetText( m_memoryValue, IntToString( m_data.m_cost ) );
		UpdateState();
		ChangeMargin();
		SetReductionArrowVisibility();
	}

	protected event OnQuickhackDescriptionUpdate( evt : QuickhackDescriptionUpdate )
	{
		m_cachedDescriptionSize = inkTextRef.GetDesiredSize( m_description );
		Expand( m_isSelected );
	}

	protected event OnSelected( itemController : weak< ListItemController > )
	{
		m_isSelected = true;
		UpdateState();
	}

	protected event OnDeselected( itemController : weak< ListItemController > )
	{
		m_isSelected = false;
		UpdateState();
	}

	private function UpdateState()
	{
		if( m_selectedLoop.IsPlaying() )
		{
			m_selectedLoop.Stop();
		}
		if( m_isSelected )
		{
			if( m_data.m_isLocked )
			{
				GetRootWidget().SetState( 'LockedSelected' );
				if( m_currentAnimationName != 'lockedSelected' )
				{
					PlayLibraryAnimation( 'loopSelected_out' );
				}
				if( !( IsChoiceAcceptedPlaying() ) )
				{
					m_selectedLoop = PlayLibraryAnimation( 'lockedSelected', GetAnimOptionsInfiniteLoop( inkanimLoopType.Cycle ) );
					m_currentAnimationName = 'lockedSelected';
				}
			}
			else
			{
				GetRootWidget().SetState( 'Selected' );
				if( m_currentAnimationName != 'loopSelected' )
				{
					PlayLibraryAnimation( 'lockedSelected_out' );
				}
				if( !( IsChoiceAcceptedPlaying() ) )
				{
					m_selectedLoop = PlayLibraryAnimation( 'loopSelected', GetAnimOptionsInfiniteLoop( inkanimLoopType.Cycle ) );
					m_currentAnimationName = 'loopSelected';
				}
			}
		}
		else
		{
			if( m_data.m_isLocked )
			{
				GetRootWidget().SetState( 'Locked' );
				m_selectedLoop = PlayLibraryAnimation( 'lockedSelected_out' );
			}
			else
			{
				GetRootWidget().SetState( 'Default' );
				m_selectedLoop = PlayLibraryAnimation( 'loopSelected_out' );
			}
		}
	}

	protected event OnUpdateAnimationState( optional e : inkAnimProxy )
	{
		UpdateState();
	}

	private function SetActionState()
	{
		inkTextRef.SetLocalizationKeyString( m_actionStateText, QuickhacksListGameController.EActionInactivityResonToLocalizationString( m_data.m_actionState ) );
		if( m_data.m_actionState == EActionInactivityReson.Ready )
		{
			inkWidgetRef.SetState( m_actionStateRoot, 'Default' );
		}
		else
		{
			inkWidgetRef.SetState( m_actionStateRoot, 'Locked' );
		}
	}

	private function SetReductionArrowVisibility()
	{
		if( m_data.m_type == gamedataObjectActionType.VehicleQuickHack )
		{
			inkImageRef.SetVisible( m_costReductionArrow, false );
		}
		else if( m_data.m_cost < m_data.m_costRaw )
		{
			inkImageRef.SetVisible( m_costReductionArrow, true );
			inkImageRef.SetBrushMirrorType( m_costReductionArrow, inkBrushMirrorType.NoMirror );
			inkImageRef.SetState( m_costReductionArrow, 'Down' );
		}
		else if( m_data.m_cost > m_data.m_costRaw )
		{
			inkImageRef.SetVisible( m_costReductionArrow, true );
			inkImageRef.SetBrushMirrorType( m_costReductionArrow, inkBrushMirrorType.Vertical );
			inkImageRef.SetState( m_costReductionArrow, 'Up' );
		}
		else
		{
			inkImageRef.SetVisible( m_costReductionArrow, false );
		}
	}

	public function UpdateCooldown( cooldown : Float )
	{
		inkTextRef.SetText( m_cooldownValue, FloatToStringPrec( cooldown, 4 ) );
		SetCooldownVisibility( true );
	}

	public function SetCooldownVisibility( isVisible : Bool )
	{
		if( inkTextRef.IsVisible( m_cooldownValue ) != isVisible )
		{
			if( isVisible )
			{
				m_data.m_actionState = EActionInactivityReson.Recompilation;
			}
			SetActionState();
			inkTextRef.SetVisible( m_cooldownValue, isVisible );
			inkWidgetRef.SetVisible( m_cooldownIcon, isVisible );
		}
	}

	private function Expand( value : Bool, optional force : Bool )
	{
		var animSizeFrom : Vector2;
		var animSizeTo : Vector2;
		if( m_expanded == value && !( force ) )
		{
			return;
		}
		m_expanded = value;
		inkTextRef.SetVisible( m_description, m_expanded );
		if( m_expanded )
		{
			inkTextRef.SetVisible( m_description, true );
		}
		if( m_resizeAnim )
		{
			m_resizeAnim.Stop();
		}
		m_resizeAnim = new inkAnimController;
		if( m_expanded )
		{
			animSizeFrom = Vector2( 0.0, 0.0 );
			animSizeTo = m_cachedDescriptionSize;
			m_resizeAnim.Select( inkWidgetRef.Get( m_descriptionSize ) ).Interpolate( 'size', animSizeFrom, animSizeTo ).Duration( m_expandAnimationDuration ).Type( inkanimInterpolationType.Exponential ).Mode( inkanimInterpolationMode.EasyOut );
			m_resizeAnim.Play();
			m_resizeAnim.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnResizingFinished' );
		}
		else
		{
			animSizeFrom = m_cachedDescriptionSize;
			animSizeTo = Vector2( 0.0, 0.0 );
			m_resizeAnim.Select( inkWidgetRef.Get( m_descriptionSize ) ).Interpolate( 'size', animSizeFrom, animSizeTo ).Duration( m_expandAnimationDuration ).Type( inkanimInterpolationType.Exponential ).Mode( inkanimInterpolationMode.EasyOut );
			m_resizeAnim.Play();
			m_resizeAnim.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnResizingFinished' );
		}
	}

	protected event OnResizingFinished( anim : inkAnimProxy )
	{
		if( !( m_expanded ) )
		{
			inkTextRef.SetVisible( m_description, false );
		}
		AdjustToTextDescriptionSize( true );
	}

	private function ShowMemoryCell( value : Int32 )
	{
		var i : Int32;
		inkCompoundRef.RemoveAllChildren( m_memoryCells );
		for( i = 0; i < 1; i += 1 )
		{
			SpawnFromLocal( ( ( inkCompoundWidget )( inkCompoundRef.Get( m_memoryCells ) ) ), 'memory_cell_small' );
		}
	}

	private function AdjustToTextDescriptionSize( value : Bool )
	{
		if( value )
		{
			inkTextRef.SetVAlign( m_description, inkEVerticalAlign.Top );
			inkTextRef.SetHAlign( m_description, inkEHorizontalAlign.Left );
			inkWidgetRef.SetVAlign( m_descriptionSize, inkEVerticalAlign.Fill );
			inkWidgetRef.SetHAlign( m_descriptionSize, inkEHorizontalAlign.Fill );
		}
		else
		{
			inkTextRef.SetVAlign( m_description, inkEVerticalAlign.Fill );
			inkTextRef.SetHAlign( m_description, inkEHorizontalAlign.Fill );
			inkWidgetRef.SetVAlign( m_descriptionSize, inkEVerticalAlign.Top );
			inkWidgetRef.SetHAlign( m_descriptionSize, inkEHorizontalAlign.Left );
		}
	}

	private function ChangeMargin()
	{
		var offset : Float;
		var index : Float;
		var angleRange : Float;
		var anglePerItem : Float;
		var angleOffset : Float;
		index = ( ( Float )( GetIndex() ) );
		angleRange = ( ( ( Float )( Min( m_data.m_maxListSize, 8 ) ) ) * 180.0 ) / 8.0;
		anglePerItem = angleRange / ( ( Float )( m_data.m_maxListSize ) );
		angleOffset = AbsF( ( angleRange * 0.5 ) - 90.0 ) + ( anglePerItem * 0.5 );
		offset = m_curveRadius * SinF( Deg2Rad( angleOffset + ( anglePerItem * ( ( Float )( index ) ) ) ) );
		m_root.SetMargin( inkMargin( -( offset ), 0.0, offset, 0.0 ) );
	}

	public function PlayChoiceAcceptedAnimation()
	{
		if( !( IsChoiceAcceptedPlaying() ) )
		{
			if( m_data.m_isLocked )
			{
				m_choiceAccepted = PlayLibraryAnimation( 'click_locked' );
			}
			else
			{
				m_choiceAccepted = PlayLibraryAnimation( 'choiceAccept' );
			}
			m_choiceAccepted.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnUpdateAnimationState' );
			if( m_currentAnimationName != 'lockedSelected' )
			{
				PlayLibraryAnimation( 'loopSelected_out' );
			}
			if( m_currentAnimationName != 'loopSelected' )
			{
				PlayLibraryAnimation( 'lockedSelected_out' );
			}
		}
	}

	private function IsChoiceAcceptedPlaying() : Bool
	{
		return m_choiceAccepted.IsPlaying();
	}

}

