class RipperdocMetersArmor extends RipperdocMetersBase
{
	default m_slopeLengthModifier = 0.25f;
	default m_barsHeigh = 9.f;
	default m_barsMargin = 9.f;
	default m_barWidgetLibraryName = 'ArmorMeterBar';
	[ category = "Armor Bars" ]
	private editable var m_barScale : Float;
	default m_barScale = 2.5f;
	[ category = "Armor Labels" ]
	private editable var m_currentArmorLabelContainer : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_currentArmorLabelBackground : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_costArmorLabelContainer : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_costArmorLabelBackground : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_costArmorLabelValue : inkTextRef;
	[ category = "Armor Labels" ]
	private editable var m_maxArmorLabel : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_maxArmorLabelContainer : inkWidgetRef;
	[ category = "Armor Labels" ]
	private editable var m_maxArmorLabelValue : inkTextRef;
	private var m_maxArmor : Float;
	private var m_curEquippedArmor : Float;
	private var m_newEquippedArmor : Float;
	private var m_maxArmorPossible : Float;
	private var m_maxDamageReduction : Float;
	private var m_currentArmorLabel : weak< RipperdocFillLabel >;
	private var m_currentArmorLabelAnimation : inkAnimProxy;
	private var m_costArmorLabelAnimation : inkAnimProxy;
	private var m_currentArmorLabelPulseAnimation : PulseAnimation;
	private var m_costArmorLabelPulseAnimation : PulseAnimation;
	private var m_maxBaseBar : Int32;
	private var m_currentBars : Int32;
	private var m_barsSpawned : Bool;
	default m_barsSpawned = false;
	private var C_costLabelAnchorPoint_ADD : Vector2;
	private var C_costLabelAnchorPoint_SUBTRACT : Vector2;
	private var C_costLabelAnchorPoint_EQUIPPED : Vector2;

	protected event OnInitialize()
	{
		var size : Vector2;
		C_costLabelAnchorPoint_EQUIPPED = Vector2( -2.20000005, -0.2 );
		C_costLabelAnchorPoint_ADD = inkWidgetRef.GetAnchorPoint( m_costArmorLabelContainer );
		C_costLabelAnchorPoint_SUBTRACT = Vector2( 1.0, -1.29999995 );
		m_currentArmorLabelPulseAnimation = new PulseAnimation;
		m_costArmorLabelPulseAnimation = new PulseAnimation;
		m_tooltipData = new RipperdocBarTooltipTooltipData;
		m_tooltipData.barType = BarType.Armor;
		m_barGaps.PushBack( 10 );
		m_barGaps.PushBack( 20 );
		m_barGaps.PushBack( 30 );
		m_barGaps.PushBack( 40 );
		m_currentArmorLabel = ( ( RipperdocFillLabel )( inkWidgetRef.GetController( m_currentArmorLabelContainer ) ) );
		inkWidgetRef.SetVisible( m_costArmorLabelContainer, false );
		inkWidgetRef.SetVisible( m_maxArmorLabelContainer, false );
		inkWidgetRef.SetVisible( m_maxArmorLabel, false );
		inkWidgetRef.SetVisible( m_currentArmorLabelContainer, false );
		SetupBarIntroAnimation();
		SetupPulseAnimParams( m_pulseAnimtopOpacity, m_pulseAnimbottomOpacity, m_pulseAnimpulseRate, m_pulseAnimdelay );
		inkWidgetRef.RegisterToCallback( m_hoverArea, 'OnHoverOver', this, 'OnBarHoverOver' );
		inkWidgetRef.RegisterToCallback( m_hoverArea, 'OnHoverOut', this, 'OnBarHoverOut' );
		size = GetRootWidget().GetSize();
		m_currentArmorLabel.Configure( size.Y );
		inkWidgetRef.SetState( m_currentArmorLabelContainer, 'Armor_Mid' );
	}

	protected event OnUninitialize()
	{
		inkWidgetRef.UnregisterFromCallback( m_hoverArea, 'OnHoverOver', this, 'OnBarHoverOver' );
		inkWidgetRef.UnregisterFromCallback( m_hoverArea, 'OnHoverOut', this, 'OnBarHoverOut' );
	}

	private function SpawnBars()
	{
		var i : Int32;
		for( i = 0; i < BAR_COUNT; i += 1 )
		{
			AsyncSpawnFromLocal( inkWidgetRef.Get( m_barAnchor ), m_barWidgetLibraryName, this, 'OnBarSpawned', NULL );
		}
	}

	protected event OnBarSpawned( widget : inkWidget, data : IScriptable )
	{
		var g : Int32;
		var controller : RipperdocNewMeterBar;
		controller = ( ( RipperdocNewMeterBar )( widget.GetController() ) );
		m_bars.PushBack( controller );
		for( g = 0; g < m_barGaps.Size(); g += 1 )
		{
			if( m_bars.Size() == m_barGaps[ g ] )
			{
				controller.GetRootWidget().UpdateMargin( 0.0, m_barGapSize, 0.0, 0.0 );
			}
		}
		m_barIntroAnimProxy = widget.PlayAnimation( m_barIntroAnimDef );
		if( m_bars.Size() == BAR_COUNT )
		{
			m_barIntroAnimProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnLastBarIntroFinished' );
		}
	}

	protected event OnLastBarIntroFinished( animProxy : inkAnimProxy )
	{
		SetArmor();
		SetMaxBar();
		inkWidgetRef.SetVisible( m_currentArmorLabelContainer, true );
		m_barIntroAnimProxy.UnregisterFromCallback( inkanimEventType.OnFinish, this, 'OnLastBarIntroFinished' );
		m_barsSpawned = true;
	}

	private function SetArmor()
	{
		var i : Int32;
		var equipBars : Int32;
		var baseBars : Int32;
		var percent : Float;
		var sizeOffset : Float;
		var delay : Float;
		percent = m_newEquippedArmor / m_maxArmorPossible;
		equipBars = Min( RoundMath( ( ( Float )( BAR_COUNT ) ) * percent ), BAR_COUNT );
		baseBars = equipBars - BAR_SLOPE_COUNT;
		m_currentArmorLabel.AnimateLabel( RoundMath( m_newEquippedArmor ), 0.2 );
		delay = BAR_DELAY_OFFSET * ( ( Float )( ( equipBars - 1 ) ) );
		for( i = 0; i < BAR_COUNT; i += 1 )
		{
			m_bars[ i ].StopPulse();
			if( i < equipBars )
			{
				m_bars[ i ].SetState( 'Armor_Mid' );
			}
			else
			{
				m_bars[ i ].SetState( 'Default' );
			}
			sizeOffset = 0.0;
			if( ( i > baseBars ) && ( i < equipBars ) )
			{
				sizeOffset = GetSlopeAnimOffset( i, baseBars );
			}
			if( sizeOffset > 0.0 )
			{
				m_bars[ i ].SetSizeAnimation( m_barScale + 0.5, sizeOffset, delay, BAR_ANIM_DURATION );
			}
			else
			{
				m_bars[ i ].SetSizeAnimation( m_barScale, 0.0, 0.0, BAR_ANIM_DURATION );
			}
			if( ( i + 1 ) < equipBars )
			{
				delay -= BAR_DELAY_OFFSET;
			}
			else if( ( i + 1 ) > equipBars )
			{
				delay += BAR_DELAY_OFFSET;
			}
			if( ( i + 1 ) == equipBars )
			{
				MoveLabelToBar( m_costArmorLabelContainer, m_bars[ i ], m_costArmorLabelAnimation, false, false );
				MoveLabelToBar( m_currentArmorLabelContainer, m_bars[ i ], m_currentArmorLabelAnimation, true, false );
			}
		}
		m_currentBars = equipBars;
		m_curEquippedArmor = m_newEquippedArmor;
		m_tooltipData.totalValue = RoundMath( m_newEquippedArmor );
		m_tooltipData.maxValue = RoundMath( m_maxArmor );
		m_tooltipData.maxDamageReduction = RoundTo( m_maxDamageReduction * 100.0, 0 );
		inkTextRef.SetText( m_maxArmorLabelValue, IntToString( RoundMath( m_maxArmor ) ) );
		inkWidgetRef.SetVisible( m_costArmorLabelContainer, false );
		StopPulse( m_currentArmorLabelPulseAnimation );
		StopPulse( m_costArmorLabelPulseAnimation );
	}

	private function SetArmorData( newEquippedArmor, maxCurrentArmor, maxArmorPossible, maxDamageReduction : Float )
	{
		m_maxArmor = maxCurrentArmor;
		m_newEquippedArmor = newEquippedArmor;
		if( m_curEquippedArmor == 0.0 )
		{
			m_curEquippedArmor = m_newEquippedArmor;
		}
		m_maxArmorPossible = maxArmorPossible;
		m_maxDamageReduction = maxDamageReduction;
		m_maxBaseBar = RoundMath( ( ( Float )( BAR_COUNT ) ) * ( ( ( Float )( m_maxArmor ) ) / m_maxArmorPossible ) );
	}

	private function SetMaxBar()
	{
		var i, g : Int32;
		var offset : Float;
		var oldMargin : inkMargin;
		i = m_maxBaseBar;
		offset = ( ( Float )( ( BAR_COUNT - i ) ) ) * ( m_barsHeigh + m_barsMargin );
		offset -= m_barsMargin;
		for( g = 0; g < m_barGaps.Size(); g += 1 )
		{
			if( m_barGaps[ g ] >= i )
			{
				offset += m_barGapSize;
			}
		}
		oldMargin = inkWidgetRef.GetMargin( m_maxArmorLabelContainer );
		inkWidgetRef.SetMargin( m_maxArmorLabelContainer, oldMargin.left, offset, oldMargin.right, oldMargin.bottom );
		inkWidgetRef.SetVisible( m_maxArmorLabelContainer, true );
	}

	private function PreviewChange( change : Float, isHover : Bool, isCyberwareEquipped : Bool )
	{
		var i : Int32;
		var index : Int32;
		var armorChange : Int32;
		var currentArmor : Int32;
		var updateRange : Int32;
		var newBars : Int32;
		var equipBars : Int32;
		var baseBars : Int32;
		var sizeOffset : Float;
		var delay : Float;
		var state : CName;
		newBars = RoundMath( ( change / m_maxArmorPossible ) * ( ( Float )( BAR_COUNT ) ) );
		equipBars = Min( m_currentBars + newBars, BAR_COUNT );
		armorChange = RoundMath( change );
		currentArmor = RoundMath( m_curEquippedArmor );
		baseBars = Min( m_currentBars - BAR_SLOPE_COUNT, BAR_COUNT - BAR_SLOPE_COUNT );
		delay = BAR_DELAY_OFFSET * ( ( Float )( BAR_SLOPE_COUNT ) );
		inkTextRef.SetState( m_costArmorLabelValue, 'Default' );
		if( !( isHover ) || ( armorChange == 0 ) )
		{
			inkWidgetRef.SetVisible( m_costArmorLabelContainer, false );
			m_currentArmorLabel.AnimateLabel( Abs( currentArmor ), 0.2 );
			StopPulse( m_currentArmorLabelPulseAnimation );
			StopPulse( m_costArmorLabelPulseAnimation );
		}
		else if( armorChange > 0 )
		{
			inkWidgetRef.SetVisible( m_costArmorLabelContainer, true );
			inkWidgetRef.SetAnchorPoint( m_costArmorLabelContainer, C_costLabelAnchorPoint_ADD );
			inkWidgetRef.SetState( m_costArmorLabelContainer, 'Safe_Add' );
			m_currentArmorLabel.AnimateLabel( Abs( currentArmor ), 0.2 );
			inkTextRef.SetText( m_costArmorLabelValue, "+" + IntToString( armorChange ) );
			StartPulse( m_costArmorLabelPulseAnimation, m_pulseAnimationParams, inkWidgetRef.Get( m_costArmorLabelContainer ) );
			StopPulse( m_currentArmorLabelPulseAnimation );
		}
		else if( isCyberwareEquipped )
		{
			inkWidgetRef.SetVisible( m_costArmorLabelContainer, true );
			inkWidgetRef.SetAnchorPoint( m_costArmorLabelContainer, C_costLabelAnchorPoint_EQUIPPED );
			inkWidgetRef.SetState( m_costArmorLabelContainer, 'Hovering_Equipped_Cyberware' );
			m_currentArmorLabel.AnimateLabel( Abs( currentArmor ), 0.2 );
			inkTextRef.SetText( m_costArmorLabelValue, IntToString( Abs( armorChange ) ) );
			StartPulse( m_costArmorLabelPulseAnimation, m_pulseAnimationParams, inkWidgetRef.Get( m_costArmorLabelContainer ) );
			StopPulse( m_currentArmorLabelPulseAnimation );
		}
		else if( armorChange < 0 )
		{
			inkWidgetRef.SetVisible( m_costArmorLabelContainer, true );
			inkWidgetRef.SetAnchorPoint( m_costArmorLabelContainer, C_costLabelAnchorPoint_SUBTRACT );
			inkWidgetRef.SetState( m_costArmorLabelContainer, 'Default' );
			m_currentArmorLabel.AnimateLabel( Abs( currentArmor ), 0.2 );
			inkTextRef.SetText( m_costArmorLabelValue, IntToString( armorChange ) );
			StartPulse( m_costArmorLabelPulseAnimation, m_pulseAnimationParams, inkWidgetRef.Get( m_costArmorLabelContainer ) );
			StopPulse( m_currentArmorLabelPulseAnimation );
		}
		updateRange = Abs( newBars ) + BAR_SLOPE_COUNT;
		for( i = 0; i <= updateRange; i += 1 )
		{
			if( armorChange >= 0 )
			{
				index = ( equipBars - updateRange ) + i;
			}
			else if( armorChange < 0 )
			{
				index = ( m_currentBars - updateRange ) + i;
			}
			if( ( ( isHover && ( newBars >= 0 ) ) && ( index >= m_currentBars ) ) && ( index < equipBars ) )
			{
				state = 'Safe_Add';
				m_bars[ index ].StartPulse( m_pulseAnimationParams );
			}
			else if( ( ( isHover && ( newBars < 0 ) ) && ( index > equipBars ) ) && ( index < m_currentBars ) )
			{
				state = 'Armor_Mid';
				m_bars[ index ].StartPulse( m_pulseAnimationParams );
			}
			else if( index < m_currentBars )
			{
				state = 'Armor_Mid';
				m_bars[ index ].StopPulse();
			}
			else
			{
				state = 'Default';
				m_bars[ index ].StopPulse();
			}
			m_bars[ index ].SetState( state );
			sizeOffset = 0.0;
			if( ( ( ( isHover && ( newBars > 0 ) ) && ( index >= m_currentBars ) ) && ( index < equipBars ) ) || ( ( ( isHover && ( newBars >= 0 ) ) && ( equipBars == 0 ) ) && ( index == 0 ) ) )
			{
				sizeOffset = GetSlopeAnimOffset( BAR_SLOPE_COUNT, 1 );
			}
			else if( ( index > baseBars ) && ( index < m_currentBars ) )
			{
				sizeOffset = GetSlopeAnimOffset( index, baseBars );
			}
			if( sizeOffset > 0.0 )
			{
				m_bars[ index ].SetSizeAnimation( m_barScale + 0.5, sizeOffset, delay, BAR_ANIM_DURATION );
			}
			else if( i < m_currentBars )
			{
				m_bars[ index ].SetSizeAnimation( m_barScale, 0.0, delay, BAR_ANIM_DURATION );
			}
			else
			{
				m_bars[ index ].SetSizeAnimation( m_barScale, 0.0, 0.0, BAR_ANIM_DURATION );
			}
			if( index == m_currentBars )
			{
				if( i == 0 )
				{
					MoveLabelToBar( m_costArmorLabelContainer, m_bars[ index + 1 ], m_costArmorLabelAnimation, false, false );
				}
				else
				{
					MoveLabelToBar( m_costArmorLabelContainer, m_bars[ index ], m_costArmorLabelAnimation, false, false );
				}
			}
		}
	}

	protected event OnIntroAnimationFinished_METER( proxy : inkAnimProxy )
	{
		proxy.UnregisterFromCallback( inkanimEventType.OnStart, this, 'OnIntroAnimationFinished_METER' );
		proxy = PlayLibraryAnimation( 'meter_intro_RIGHT' );
		proxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnMeterIntroFinished_RIGHT' );
	}

	protected event OnMeterIntroFinished_RIGHT( proxy : inkAnimProxy )
	{
		QueueEvent( new ArmorBarFinalizedEvent );
		proxy.UnregisterFromCallback( inkanimEventType.OnFinish, this, 'OnMeterIntroFinished_RIGHT' );
	}

	protected event OnApply( evt : RipperdocMeterArmorApplyEvent )
	{
		SetArmorData( evt.ArmorData.CurrentArmor, evt.ArmorData.CurrentMaxArmor, evt.ArmorData.MaxArmorPossible, evt.ArmorData.MaxDamageReduction );
		if( !( m_barsSpawned ) )
		{
			SpawnBars();
		}
		else
		{
			SetArmor();
			SetMaxBar();
		}
	}

	protected event OnHover( evt : RipperdocMeterArmorHoverEvent )
	{
		var armorChange : Float;
		var equippedArmorCost : Float;
		var currentFalt : Float;
		if( ( evt.EquippedArmorChange > 0.0 ) || ( evt.EquippedArmorMultiplier > 0.0 ) )
		{
			equippedArmorCost = evt.EquippedArmorChange + ( ( m_curEquippedArmor * evt.EquippedArmorMultiplier ) / ( 1.0 + evt.EquippedArmorMultiplier ) );
			armorChange = evt.ArmorChange + ( ( ( m_curEquippedArmor - equippedArmorCost ) + evt.ArmorChange ) * evt.ArmorMultiplier );
			armorChange = armorChange - equippedArmorCost;
			if( evt.EquippedArmorMultiplier == 0.0 )
			{
				armorChange = armorChange + ( armorChange * evt.CurrentArmorMultiplier );
			}
		}
		else
		{
			currentFalt = m_curEquippedArmor / ( 1.0 + evt.CurrentArmorMultiplier );
			armorChange = ( ( currentFalt + evt.ArmorChange ) * ( ( 1.0 + evt.CurrentArmorMultiplier ) + evt.ArmorMultiplier ) ) - m_curEquippedArmor;
		}
		PreviewChange( armorChange, evt.IsHover, evt.isCyberwareEquipped );
	}

	protected event OnBarHoverOver( evt : inkPointerEvent )
	{
		super.OnBarHoverOver( evt );
		inkWidgetRef.SetVisible( m_maxArmorLabel, true );
	}

	protected event OnBarHoverOut( evt : inkPointerEvent )
	{
		super.OnBarHoverOut( evt );
		inkWidgetRef.SetVisible( m_maxArmorLabel, false );
	}

	protected event OnRipperdocMeterArmorBarHoverEvent( evt : RipperdocMeterArmorBarHoverEvent )
	{
		OnBarHoverOver( new inkPointerEvent );
	}

}

class RipperdocMeterArmorHoverEvent extends Event
{
	var IsHover : Bool;
	var ArmorChange : Float;
	var ArmorMultiplier : Float;
	var CurrentArmorMultiplier : Float;
	var EquippedArmorChange : Float;
	var EquippedArmorMultiplier : Float;
	var isCyberwareEquipped : Bool;
}

class RipperdocMeterArmorApplyEvent extends Event
{
	var ArmorData : RipperdocArmorData;
	var IsPurchase : Bool;
}

class RipperdocMeterArmorBarHoverEvent extends Event
{
}

class RipperdocArmorData
{
	var CurrentArmor : Float;
	var CurrentMaxArmor : Float;
	var MaxArmorPossible : Float;
	var MaxDamageReduction : Float;
}

