class DrawNetworkSquadEvent extends Event
{
	var shouldDraw : Bool;
	var memberID : PersistentID;
	var fxResource : FxResource;
	var isPing : Bool;
	var revealMaster : Bool;
	var revealSlave : Bool;
	var memberOnly : Bool;
	var duration : Float;
}

importonly class CommunityProxyPSPresentEvent extends Event
{
}

class CommunityProxyPS extends MasterControllerPS
{
	default m_hasNetworkBackdoor = true;
	default m_revealDevicesGrid = false;
	default m_drawGridLink = false;

	protected event OnInstantiated()
	{
		super.OnInstantiated();
	}

	protected override function Initialize()
	{
		super.Initialize();
		InitializeConnectionWithCommunity();
	}

	public export function OnCommunityProxyPSPresent( evt : CommunityProxyPSPresentEvent ) : EntityNotificationType
	{
		InitializeConnectionWithCommunity();
		return EntityNotificationType.DoNotNotifyEntity;
	}

	private function QueuePSEvent( deviceLink : DeviceLink, evt : Event )
	{
		GetPersistencySystem().QueuePSEvent( DeviceLink.GetLinkID( deviceLink ), DeviceLink.GetLinkClassName( deviceLink ), evt );
	}

	protected function InitializeConnectionWithCommunity()
	{
		var npcs : array< EntityID >;
		var i : Int32;
		npcs = ExtractEntityIDs();
		GameInstance.GetEntitySpawnerEventsBroadcaster( GetGameInstance() ).RegisterSpawnerEventPSListener( GetMyEntityID(), '', GetID(), GetClassName() );
		for( i = 0; i < npcs.Size(); i += 1 )
		{
			EstablishLink( npcs[ i ] );
		}
	}

	public export function OnGameEntitySpawnerEvent( evt : gameEntitySpawnerEvent ) : EntityNotificationType
	{
		if( evt.eventType == gameEntitySpawnerEventType.Spawn )
		{
			EstablishLink( evt.spawnedEntityId );
			if( !( IsFinal() ) )
			{
			}
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	private const function EstablishLink( targetID : EntityID )
	{
		var request : DeviceLinkRequest;
		request = DeviceLinkRequest.Construct( GetID(), GetClassName() );
		GetPersistencySystem().QueueEntityEvent( targetID, request );
	}

	public constexpr const function GetNPCsConnectedToThisAPCount() : Int32
	{
		return 666;
	}

	protected const function GetPuppetEntity( id : EntityID ) : weak< ScriptedPuppet >
	{
		return ( ( ScriptedPuppet )( GameInstance.FindEntityByID( GetGameInstance(), id ) ) );
	}

	public const function IsOfficer( id : EntityID ) : Bool
	{
		var puppet : ScriptedPuppet;
		puppet = GetPuppetEntity( id );
		if( puppet )
		{
			return puppet.IsOfficer();
		}
		else
		{
			return false;
		}
	}

	public const function DrawNetworkSquad( shouldDraw : Bool, fxResource : FxResource, memberID : PersistentID, isPing : Bool, revealMaster : Bool, revealSlave : Bool, memberOnly : Bool, optional duration : Float )
	{
		var drawNetworkSquadEvent : DrawNetworkSquadEvent;
		drawNetworkSquadEvent = new DrawNetworkSquadEvent;
		drawNetworkSquadEvent.shouldDraw = shouldDraw;
		drawNetworkSquadEvent.memberID = memberID;
		drawNetworkSquadEvent.fxResource = fxResource;
		drawNetworkSquadEvent.isPing = isPing;
		drawNetworkSquadEvent.revealMaster = revealMaster;
		drawNetworkSquadEvent.revealSlave = revealSlave;
		drawNetworkSquadEvent.memberOnly = memberOnly;
		drawNetworkSquadEvent.duration = duration;
		GetPersistencySystem().QueuePSEvent( GetID(), GetClassName(), drawNetworkSquadEvent );
	}

	public function OnDrawNetworkSquadEvent( evt : DrawNetworkSquadEvent ) : EntityNotificationType
	{
		var registerLinkRequest : RegisterNetworkLinkRequest;
		var newLink : SNetworkLinkData;
		var membersIDs : array< EntityID >;
		var officerID : EntityID;
		var i : Int32;
		var puppet : ScriptedPuppet;
		registerLinkRequest = new RegisterNetworkLinkRequest;
		membersIDs = ExtractEntityIDs();
		for( i = 0; i < membersIDs.Size(); i += 1 )
		{
			if( IsOfficer( membersIDs[ i ] ) )
			{
				officerID = membersIDs[ i ];
				membersIDs.Erase( i );
				break;
			}
		}
		puppet = GetPuppetEntity( officerID );
		if( puppet == NULL )
		{
			return EntityNotificationType.DoNotNotifyEntity;
		}
		newLink.fxResource = evt.fxResource;
		newLink.masterID = officerID;
		newLink.isDynamic = true;
		newLink.drawLink = evt.shouldDraw;
		newLink.fxResource = evt.fxResource;
		newLink.linkType = ELinkType.NETWORK;
		newLink.isPing = evt.isPing;
		newLink.masterPos = puppet.GetWorldPosition();
		newLink.lifetime = evt.duration;
		newLink.revealMaster = evt.revealMaster;
		newLink.revealSlave = evt.revealSlave;
		for( i = 0; i < membersIDs.Size(); i += 1 )
		{
			if( evt.memberOnly && ( membersIDs[ i ] != PersistentID.ExtractEntityID( evt.memberID ) ) )
			{
				continue;
			}
			puppet = GetPuppetEntity( membersIDs[ i ] );
			if( puppet == NULL )
			{
				continue;
			}
			newLink.slaveID = membersIDs[ i ];
			newLink.slavePos = puppet.GetWorldPosition();
			registerLinkRequest.linksData.PushBack( newLink );
		}
		if( registerLinkRequest.linksData.Size() > 0 )
		{
			GetNetworkSystem().QueueRequest( registerLinkRequest );
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public override function OnSecuritySystemOutput( evt : SecuritySystemOutput ) : EntityNotificationType
	{
		var npcs : array< EntityID >;
		var i : Int32;
		npcs = ExtractEntityIDs();
		for( i = 0; i < npcs.Size(); i += 1 )
		{
			GetPersistencySystem().QueueEntityEvent( npcs[ i ], evt );
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public export override function OnSecurityAreaCrossingPerimeter( evt : SecurityAreaCrossingPerimeter ) : EntityNotificationType
	{
		var i : Int32;
		var npcs : array< EntityID >;
		npcs = ExtractEntityIDs();
		for( i = 0; i < npcs.Size(); i += 1 )
		{
			if( EntityID.IsDefined( npcs[ i ] ) )
			{
				GetPersistencySystem().QueueEntityEvent( npcs[ i ], evt );
			}
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public override function OnTargetAssessmentRequest( evt : TargetAssessmentRequest ) : EntityNotificationType
	{
		var i : Int32;
		var npcs : array< EntityID >;
		npcs = ExtractEntityIDs();
		for( i = 0; i < npcs.Size(); i += 1 )
		{
			if( EntityID.IsDefined( npcs[ i ] ) )
			{
				GetPersistencySystem().QueueEntityEvent( npcs[ i ], evt );
			}
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public export override function OnSetExposeQuickHacks( evt : SetExposeQuickHacks ) : EntityNotificationType
	{
		super.OnSetExposeQuickHacks( evt );
		ForwardActionToNPCs( evt );
		ForwardActionToVehicles( evt );
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public function OnNPCBreachEvent( evt : NPCBreachEvent ) : EntityNotificationType
	{
		var aps : array< AccessPointControllerPS >;
		var i : Int32;
		aps = GetAccessPoints();
		for( i = 0; i < aps.Size(); i += 1 )
		{
			GameInstance.GetPersistencySystem( GetGameInstance() ).QueuePSEvent( aps[ i ].GetID(), aps[ i ].GetClassName(), evt );
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public const function ExtractEntityIDs() : array< EntityID >
	{
		var spawnerRecordsIDs : array< EntityID >;
		var communityEntryNames : array< CName >;
		var spawnerID : EntityID;
		spawnerID = GetMyEntityID();
		GetFixedEntityIdsFromSpawnerEntityID( spawnerID, communityEntryNames, GetGameInstance(), spawnerRecordsIDs );
		if( !( IsFinal() ) && ( spawnerRecordsIDs.Size() == 0 ) )
		{
		}
		return spawnerRecordsIDs;
	}

	private const function ForwardActionToNPCs( action : DeviceAction )
	{
		var communityNPCs : array< EntityID >;
		var i : Int32;
		communityNPCs = ExtractEntityIDs();
		for( i = 0; i < communityNPCs.Size(); i += 1 )
		{
			GetPersistencySystem().QueuePSEvent( communityNPCs[ i ], 'ScriptedPuppetPS', action );
		}
	}

	private const function ForwardActionToVehicles( action : DeviceAction )
	{
		var vehicles : array< EntityID >;
		var i : Int32;
		vehicles = ExtractEntityIDs();
		for( i = 0; i < vehicles.Size(); i += 1 )
		{
			GetPersistencySystem().QueuePSEvent( CreatePersistentID( vehicles[ i ], 'controller' ), 'VehicleComponentPS', action );
		}
	}

}

