class PuppetAction extends ScriptableDeviceAction
{

	public override function GetTweakDBChoiceRecord() : String
	{
		var interactionIDString : String;
		if( GetObjectActionRecord() && GetObjectActionRecord().ObjectActionUI() )
		{
			interactionIDString = GetObjectActionRecord().ObjectActionUI().Name();
		}
		return interactionIDString;
	}

	public override function GetTweakDBChoiceID() : TweakDBID
	{
		var id : TweakDBID;
		if( GetObjectActionRecord() && GetObjectActionRecord().ObjectActionUI() )
		{
			id = GetObjectActionRecord().ObjectActionUI().GetID();
		}
		return id;
	}

	public const override function GetObjectActionRecord() : weak< ObjectAction_Record >
	{
		return TweakDBInterface.GetObjectActionRecord( m_objectActionID );
	}

}

class AIQuickHackAction extends PuppetAction
{
	var m_target : weak< GameObject >;
	var m_scaleUploadTime : Bool;
	default m_scaleUploadTime = true;
	var m_HUDData : HUDProgressBarData;

	protected virtual function SetRegenBehavior( gameInstance : GameInstance )
	{
		var activationTime : Float;
		var regenMod : StatPoolModifier;
		var statValue : Float;
		var distanceToTarget, multiplier : Float;
		GameInstance.GetStatPoolsSystem( gameInstance ).GetModifier( GetRequesterID(), gamedataStatPoolType.QuickHackUpload, gameStatPoolModificationTypes.Regeneration, regenMod );
		if( m_scaleUploadTime )
		{
			statValue = GameInstance.GetStatsSystem( m_target.GetGame() ).GetStatValue( m_target.GetEntityID(), gamedataStatType.NPCUploadTime );
			distanceToTarget = Vector4.Distance( m_executor.GetWorldPosition(), GameInstance.FindEntityByID( gameInstance, m_requesterID ).GetWorldPosition() );
			multiplier = PowF( 1.01999998, distanceToTarget );
		}
		else
		{
			statValue = 1.0;
			multiplier = 1.0;
		}
		activationTime = GetActivationTime();
		regenMod.enabled = true;
		regenMod.valuePerSec = 100.0 / ( ( multiplier * activationTime ) * statValue );
		regenMod.rangeEnd = 100.0;
		GameInstance.GetStatPoolsSystem( gameInstance ).RequestSettingModifier( GetRequesterID(), gamedataStatPoolType.QuickHackUpload, gameStatPoolModificationTypes.Regeneration, regenMod );
	}

	private override function StartUpload( gameInstance : GameInstance )
	{
		var statPoolSys : StatPoolsSystem;
		var npcToNpcListener : UploadFromNPCToNPCListener;
		var npcToPlayerListener : UploadFromNPCToPlayerListener;
		var uploadListener : QuickHackUploadListener;
		var statMod : gameStatModifierData;
		var requesterGO : GameObject;
		requesterGO = ( ( GameObject )( GameInstance.FindEntityByID( gameInstance, m_requesterID ) ) );
		statPoolSys = GameInstance.GetStatPoolsSystem( gameInstance );
		if( requesterGO.IsPlayer() )
		{
			npcToPlayerListener = new UploadFromNPCToPlayerListener;
			npcToPlayerListener.m_npcPuppet = ( ( ScriptedPuppet )( m_executor ) );
			npcToPlayerListener.m_playerPuppet = ( ( ScriptedPuppet )( requesterGO ) );
			npcToPlayerListener.m_HUDData = m_HUDData;
			uploadListener = npcToPlayerListener;
		}
		else
		{
			npcToNpcListener = new UploadFromNPCToNPCListener;
			npcToNpcListener.m_npcPuppet = ( ( ScriptedPuppet )( m_executor ) );
			uploadListener = npcToNpcListener;
		}
		uploadListener.m_action = this;
		uploadListener.m_gameInstance = gameInstance;
		statMod = RPGManager.CreateStatModifier( gamedataStatType.QuickHackUpload, gameStatModifierType.Additive, GetActivationTime() );
		GameInstance.GetStatsSystem( gameInstance ).RemoveAllModifiers( m_requesterID, gamedataStatType.QuickHackUpload );
		GameInstance.GetStatsSystem( gameInstance ).AddModifier( m_requesterID, statMod );
		statPoolSys.RequestSettingStatPoolValue( m_requesterID, gamedataStatPoolType.QuickHackUpload, 0.0, m_executor );
		statPoolSys.RequestRegisteringListener( m_requesterID, gamedataStatPoolType.QuickHackUpload, uploadListener );
		statPoolSys.RequestAddingStatPool( m_requesterID, T"BaseStatPools.BaseQuickHackUpload" );
		uploadListener.Initialize();
		SetRegenBehavior( gameInstance );
	}

	protected override function ProcessStatusEffects( const actionEffects : ref< array< weak< ObjectActionEffect_Record > > >, gameInstance : GameInstance )
	{
		super.ProcessStatusEffects( actionEffects, gameInstance );
	}

}

class LinkedStatusEffectListener extends ScriptStatusEffectListener
{
	var instigatorObject : weak< GameObject >;
	var linkedEffect : TweakDBID;
	var evt : RemoveLinkedStatusEffectsEvent;

	public virtual function OnStatusEffectRemoved( statusEffect : weak< StatusEffect_Record > ) {}
}

class PingSquad extends PuppetAction
{
	private var m_shouldForward : Bool;
	default m_shouldForward = true;

	public const function ShouldForward() : Bool
	{
		return m_shouldForward;
	}

	public function SetShouldForward( shouldForward : Bool )
	{
		m_shouldForward = shouldForward;
	}

}

class AccessBreach extends PuppetAction
{
	var m_attempt : Int32;
	var m_networkName : String;
	var m_npcCount : Int32;
	var m_isRemote : Bool;
	var m_isSuicide : Bool;

	public function SetProperties( const networkName : ref< String >, npcCount : Int32, attemptsCount : Int32, isRemote : Bool, isSuicide : Bool )
	{
		m_networkName = networkName;
		m_npcCount = npcCount;
		m_attempt = attemptsCount;
		m_isRemote = isRemote;
		m_isSuicide = isSuicide;
	}

	public function SetAttemptCount( amount : Int32 )
	{
		m_attempt = amount;
	}

	private override function StartUpload( gameInstance : GameInstance )
	{
		var statPoolSys : StatPoolsSystem;
		var breachListener : AccessBreachListener;
		var statMod : gameStatModifierData;
		statPoolSys = GameInstance.GetStatPoolsSystem( gameInstance );
		statMod = RPGManager.CreateStatModifier( gamedataStatType.QuickHackUpload, gameStatModifierType.Additive, 1.0 );
		GameInstance.GetStatsSystem( gameInstance ).RemoveAllModifiers( m_requesterID, gamedataStatType.QuickHackUpload );
		GameInstance.GetStatsSystem( gameInstance ).AddModifier( m_requesterID, statMod );
		breachListener = new AccessBreachListener;
		breachListener.m_action = this;
		breachListener.m_gameInstance = gameInstance;
		statPoolSys.RequestRegisteringListener( m_requesterID, gamedataStatPoolType.QuickHackUpload, breachListener );
		statPoolSys.RequestAddingStatPool( m_requesterID, T"BaseStatPools.BaseQuickHackUpload" );
	}

	private override function CompleteAction( gameInstance : GameInstance )
	{
		super.CompleteAction( gameInstance );
		GetNetworkBlackboard( gameInstance ).SetInt( GetNetworkBlackboardDef().DevicesCount, m_npcCount );
		GetNetworkBlackboard( gameInstance ).SetBool( GetNetworkBlackboardDef().OfficerBreach, true );
		GetNetworkBlackboard( gameInstance ).SetBool( GetNetworkBlackboardDef().RemoteBreach, m_isRemote );
		GetNetworkBlackboard( gameInstance ).SetBool( GetNetworkBlackboardDef().SuicideBreach, m_isSuicide );
		GetNetworkBlackboard( gameInstance ).SetString( GetNetworkBlackboardDef().NetworkName, m_networkName );
		GetNetworkBlackboard( gameInstance ).SetEntityID( GetNetworkBlackboardDef().DeviceID, GetRequesterID() );
		GetNetworkBlackboard( gameInstance ).SetInt( GetNetworkBlackboardDef().Attempt, m_attempt );
		SendNanoWireBreachEventToPSM( 'NanoWireRemoteBreach', true, gameInstance );
	}

	private function GetNetworkBlackboard( gameInstance : GameInstance ) : IBlackboard
	{
		return GameInstance.GetBlackboardSystem( gameInstance ).Get( GetNetworkBlackboardDef() );
	}

	private function GetNetworkBlackboardDef() : NetworkBlackboardDef
	{
		return GetAllBlackboardDefs().NetworkBlackboard;
	}

	private function SendNanoWireBreachEventToPSM( id : CName, isActive : Bool, gameInstance : GameInstance )
	{
		var psmEvent : PSMPostponedParameterBool;
		psmEvent = new PSMPostponedParameterBool;
		psmEvent.id = id;
		psmEvent.value = isActive;
		GameInstance.GetPlayerSystem( gameInstance ).GetLocalPlayerMainGameObject().QueueEvent( psmEvent );
	}

}

