struct Agent
{
	[ unsavable = "true" ]
	persistent var link : DeviceLink;
	[ unsavable = "true" ]
	persistent var reprimands : array< ReprimandData >;
	[ unsavable = "true" ]
	persistent var supportingAgents : array< PersistentID >;
	[ unsavable = "true" ]
	persistent var areas : array< DeviceLink >;
	[ unsavable = "true" ]
	persistent var incomingFilter : EFilterType;
	[ unsavable = "true" ]
	persistent var cachedDelayDuration : Float;

	public static function Construct( link : DeviceLink, const areas : ref< array< SecurityAreaControllerPS > > ) : Agent
	{
		var agent : Agent;
		var i : Int32;
		if( !( DeviceLink.IsValid( link ) ) || ( areas.Size() == 0 ) )
		{
			return agent;
		}
		agent.link = link;
		Agent.SetIncomingFilter( agent, areas );
		if( DeviceLink.GetLinkClassName( link ) == 'PuppetDeviceLinkPS' )
		{
			agent.cachedDelayDuration = RandRangeF( 0.1, 1.0 );
		}
		for( i = 0; i < areas.Size(); i += 1 )
		{
			agent.areas.PushBack( DeviceLink.Construct( areas[ i ] ) );
		}
		return agent;
	}

	public static function AddArea( self : ref< Agent >, area : SecurityAreaControllerPS )
	{
		Agent.SetIncomingFilter( self, area );
		self.areas.PushBack( DeviceLink.Construct( area ) );
	}

	public static function RemoveArea( self : ref< Agent >, const remainingAreas : ref< array< SecurityAreaControllerPS > > )
	{
		var i : Int32;
		Agent.SetIncomingFilter( self, remainingAreas );
		self.areas.Clear();
		for( i = 0; i < remainingAreas.Size(); i += 1 )
		{
			self.areas.PushBack( DeviceLink.Construct( remainingAreas[ i ] ) );
		}
	}

	public static function SetIncomingFilter( self : ref< Agent >, const areas : ref< array< SecurityAreaControllerPS > > )
	{
		var i : Int32;
		self.incomingFilter = EFilterType.ALLOW_ALL;
		for( i = 0; i < areas.Size(); i += 1 )
		{
			Agent.SetIncomingFilter( self, areas[ i ] );
		}
	}

	public static function SetIncomingFilter( self : ref< Agent >, area : SecurityAreaControllerPS )
	{
		if( ( ( Int32 )( self.incomingFilter ) ) < ( ( Int32 )( area.GetIncomingFilter() ) ) )
		{
			self.incomingFilter = area.GetIncomingFilter();
		}
	}

	public static function IsValid( self : Agent ) : Bool
	{
		if( DeviceLink.IsValid( self.link ) && ( self.areas.Size() != 0 ) )
		{
			return true;
		}
		return false;
	}

	public static function GetAreas( const self : ref< Agent >, areas : ref< array< DeviceLink > > )
	{
		var i : Int32;
		for( i = 0; i < self.areas.Size(); i += 1 )
		{
			areas.PushBack( self.areas[ i ] );
		}
	}

	public static function IsEligible( const self : ref< Agent >, state : ESecuritySystemState, const breachedAreas : ref< array< SecurityAreaControllerPS > >, inputsOutgoingFilter : EFilterType, out breachOrigin : EBreachOrigin ) : Bool
	{
		var i, k : Int32;
		breachOrigin = EBreachOrigin.EXTERNAL;
		for( i = 0; i < breachedAreas.Size(); i += 1 )
		{
			for( k = 0; k < self.areas.Size(); k += 1 )
			{
				if( breachedAreas[ i ] == self.areas[ k ] )
				{
					breachOrigin = EBreachOrigin.LOCAL;
					return true;
				}
			}
		}
		if( inputsOutgoingFilter == EFilterType.ALLOW_ALL )
		{
			if( self.incomingFilter == EFilterType.ALLOW_ALL )
			{
				return true;
			}
			if( self.incomingFilter == EFilterType.ALLOW_COMBAT_ONLY && state == ESecuritySystemState.COMBAT )
			{
				return true;
			}
			return false;
		}
		if( inputsOutgoingFilter == EFilterType.ALLOW_COMBAT_ONLY )
		{
			if( self.incomingFilter == EFilterType.ALLOW_ALL )
			{
				return true;
			}
			if( self.incomingFilter == EFilterType.ALLOW_COMBAT_ONLY && state == ESecuritySystemState.COMBAT )
			{
				return true;
			}
			return false;
		}
		return false;
	}

	public static function IsEligibleToShareData( const self : ref< Agent >, state : ESecuritySystemState, const breachedAreas : ref< array< SecurityAreaControllerPS > >, inputsOutgoingFilter : EFilterType ) : Bool
	{
		var i, k : Int32;
		if( inputsOutgoingFilter == EFilterType.ALLOW_ALL )
		{
			if( self.incomingFilter == EFilterType.ALLOW_ALL )
			{
				return true;
			}
			if( self.incomingFilter == EFilterType.ALLOW_COMBAT_ONLY && state == ESecuritySystemState.COMBAT )
			{
				return true;
			}
		}
		if( inputsOutgoingFilter == EFilterType.ALLOW_COMBAT_ONLY )
		{
			if( self.incomingFilter == EFilterType.ALLOW_ALL )
			{
				return true;
			}
			if( self.incomingFilter == EFilterType.ALLOW_COMBAT_ONLY && state == ESecuritySystemState.COMBAT )
			{
				return true;
			}
		}
		for( i = 0; i < breachedAreas.Size(); i += 1 )
		{
			for( k = 0; k < self.areas.Size(); k += 1 )
			{
				if( breachedAreas[ i ] == self.areas[ k ] )
				{
					return true;
				}
			}
		}
		return false;
	}

	public static function AddSupport( self : ref< Agent >, id : PersistentID, shouldAdd : Bool ) : Bool
	{
		var i : Int32;
		if( shouldAdd )
		{
			for( i = 0; i < self.supportingAgents.Size(); i += 1 )
			{
				if( self.supportingAgents[ i ] == id )
				{
					return false;
				}
			}
			self.supportingAgents.PushBack( id );
			if( self.supportingAgents.Size() == 1 )
			{
				return true;
			}
			return false;
		}
		else
		{
			for( i = 0; i < self.supportingAgents.Size(); i += 1 )
			{
				if( self.supportingAgents[ i ] == id )
				{
					self.supportingAgents.EraseFast( i );
					if( self.supportingAgents.Size() == 0 )
					{
						return true;
					}
					return false;
				}
			}
			return false;
		}
	}

	public static function HasSupport( const self : ref< Agent > ) : Bool
	{
		return self.supportingAgents.Size() > 0;
	}

	public static function ClearSupport( self : ref< Agent > )
	{
		self.supportingAgents.Clear();
	}

	public static function IsPerformingReprimand( const self : ref< Agent > ) : Bool
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( self.reprimands[ i ].isActive )
			{
				return true;
			}
		}
		return false;
	}

	public static function IsPerformingReprimandAgainst( const self : ref< Agent >, target : EntityID ) : Bool
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( ( self.reprimands[ i ].receiver == target ) && self.reprimands[ i ].isActive )
			{
				return true;
			}
		}
		return false;
	}

	public static function GetReprimandReceiver( const self : ref< Agent > ) : EntityID
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( self.reprimands[ i ].isActive )
			{
				return self.reprimands[ i ].receiver;
			}
		}
		return EMPTY_ENTITY_ID();
	}

	public static function GetReprimandsCount( const self : ref< Agent >, target : EntityID ) : Int32
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( self.reprimands[ i ].receiver == target )
			{
				return self.reprimands[ i ].count;
			}
		}
		return 0;
	}

	public static function ReleaseFromReprimand( self : ref< Agent >, target : EntityID )
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( self.reprimands[ i ].receiver == target )
			{
				self.reprimands[ i ].isActive = false;
			}
		}
	}

	public static function ForceRelaseReprimands( self : ref< Agent > )
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			self.reprimands[ i ].isActive = false;
		}
	}

	public static function StoreReprimand( self : ref< Agent >, reprimandData : ReprimandData )
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( ( self.reprimands[ i ].receiver == reprimandData.receiver ) && ( self.reprimands[ i ].reprimandID != reprimandData.reprimandID ) )
			{
				self.reprimands[ i ].count += 1;
				self.reprimands[ i ].reprimandID = reprimandData.reprimandID;
				self.reprimands[ i ].isActive = true;
				return;
			}
		}
		reprimandData.count = 1;
		self.reprimands.PushBack( reprimandData );
		return;
	}

	public static function WipeReprimand( self : ref< Agent >, target : EntityID )
	{
		var i : Int32;
		for( i = 0; i < self.reprimands.Size(); i += 1 )
		{
			if( self.reprimands[ i ].receiver == target )
			{
				self.reprimands.EraseFast( i );
				return;
			}
		}
	}

	public static function WipeReprimand( self : ref< Agent >, attGroup : CName, attSystem : AttitudeSystem )
	{
		var i : Int32;
		for( i = self.reprimands.Size() - 1; i >= 0; i -= 1 )
		{
			if( attSystem.GetAttitudeRelation( attGroup, self.reprimands[ i ].receiverAttitudeGroup ) == EAIAttitude.AIA_Friendly )
			{
				self.reprimands.Erase( i );
			}
		}
	}

}

