class ReflexesMasterPerk1EffectorListener extends ScriptedDamageSystemListener
{
	var m_owner : ReflexesMasterPerk1Effector;

	protected override function OnHitTriggered( hitEvent : gameHitEvent )
	{
		m_owner.StoreHitEvent( hitEvent );
	}

	protected override function OnMissTriggered( missEvent : gameMissEvent )
	{
		m_owner.ClearHistory();
	}

	protected override function OnHitReceived( hitEvent : gameHitEvent ) {}

	protected override function OnPipelineProcessed( hitEvent : gameHitEvent ) {}
}

class ReflexesMasterPerk1Effector extends ModifyAttackEffector
{
	private var m_operationType : EMathOperator;
	private var m_value : Float;
	private var m_timeOut : Float;
	private var m_damageHistory : array< gameHitEvent >;
	private var m_listener : ReflexesMasterPerk1EffectorListener;
	private var m_lastTargetID : EntityID;

	public function StoreHitEvent( hitEvent : gameHitEvent )
	{
		var targetID : EntityID;
		targetID = hitEvent.target.GetEntityID();
		if( hitEvent.attackData.HasFlag( hitFlag.ReflexesMasterPerk1 ) )
		{
			return;
		}
		if( !( EntityID.IsDefined( m_lastTargetID ) ) )
		{
			m_lastTargetID = targetID;
		}
		if( targetID != m_lastTargetID )
		{
			ClearHistory();
		}
		else if( m_damageHistory.Size() > 0 )
		{
			if( ( hitEvent.attackData.GetAttackTime() - m_damageHistory[ ( m_damageHistory.Size() - 1 ) ].attackData.GetAttackTime() ) > m_timeOut )
			{
				ClearHistory();
			}
		}
		m_lastTargetID = targetID;
		m_damageHistory.PushBack( hitEvent );
	}

	public function ClearHistory()
	{
		m_damageHistory.Clear();
	}

	protected override function Initialize( record : TweakDBID, game : GameInstance, parentRecord : TweakDBID )
	{
		var str : String;
		var player : GameObject;
		player = GameInstance.GetPlayerSystem( game ).GetLocalPlayerControlledGameObject();
		str = TweakDBInterface.GetString( record + T".operationType", "" );
		m_operationType = ( ( EMathOperator )( ( ( Int32 )( EnumValueFromString( "EMathOperator", str ) ) ) ) );
		m_value = TweakDBInterface.GetFloat( record + T".multiplier", 0.0 );
		m_timeOut = TweakDBInterface.GetFloat( record + T".timeOut", 0.0 );
		m_listener = new ReflexesMasterPerk1EffectorListener;
		m_listener.m_owner = this;
		GameInstance.GetDamageSystem( game ).RegisterSyncListener( m_listener, player.GetEntityID(), gameDamageCallbackType.HitTriggered, gameDamagePipelineStage.Process, DMGPipelineType.Damage );
		GameInstance.GetDamageSystem( game ).RegisterSyncListener( m_listener, player.GetEntityID(), gameDamageCallbackType.MissTriggered, gameDamagePipelineStage.Process, DMGPipelineType.Damage );
	}

	protected override function Uninitialize( game : GameInstance )
	{
		var player : GameObject;
		player = GameInstance.GetPlayerSystem( game ).GetLocalPlayerControlledGameObject();
		GameInstance.GetDamageSystem( game ).UnregisterSyncListener( m_listener, player.GetEntityID(), gameDamageCallbackType.HitTriggered, gameDamagePipelineStage.Process, DMGPipelineType.Damage );
		GameInstance.GetDamageSystem( game ).UnregisterSyncListener( m_listener, player.GetEntityID(), gameDamageCallbackType.MissTriggered, gameDamagePipelineStage.Process, DMGPipelineType.Damage );
	}

	protected override function ActionOn( owner : GameObject )
	{
		var hitEvent : gameHitEvent;
		hitEvent = GetHitEvent();
		if( hitEvent )
		{
			ModifyDamage( hitEvent, m_operationType, m_value );
		}
		ClearHistory();
	}

	protected override function RepeatedAction( owner : GameObject )
	{
		var hitEvent : gameHitEvent;
		hitEvent = GetHitEvent();
		if( hitEvent )
		{
			ModifyDamage( hitEvent, m_operationType, m_value );
		}
		ClearHistory();
	}

	protected function ModifyDamage( hitEvent : gameHitEvent, operationType : EMathOperator, value : Float )
	{
		var i : Int32;
		var accumulatedDamage : Float;
		accumulatedDamage = 0.0;
		for( i = 0; i < m_damageHistory.Size(); i += 1 )
		{
			accumulatedDamage += m_damageHistory[ i ].attackComputed.GetTotalAttackValue( gamedataStatPoolType.Health );
		}
		accumulatedDamage = accumulatedDamage * value;
		switch( operationType )
		{
			case EMathOperator.Add:
				hitEvent.attackComputed.AddAttackValue( accumulatedDamage, gamedataDamageType.Physical );
			break;
			case EMathOperator.Subtract:
				hitEvent.attackComputed.AddAttackValue( -( accumulatedDamage ), gamedataDamageType.Physical );
			break;
			case EMathOperator.Multiply:
				hitEvent.attackComputed.MultAttackValue( accumulatedDamage, gamedataDamageType.Physical );
			break;
			case EMathOperator.Divide:
				hitEvent.attackComputed.MultAttackValue( 1.0 / accumulatedDamage, gamedataDamageType.Physical );
			break;
			default:
				return;
		}
		hitEvent.attackData.AddFlag( hitFlag.Special, 'ReflexesMasterPerk1Effector' );
		hitEvent.attackData.AddFlag( hitFlag.ReflexesMasterPerk1, 'ReflexesMasterPerk1Effector' );
	}

}

