class FollowSlot extends IScriptable
{
	var id : Int32;
	instanceeditable var slotTransform : Transform;
	instanceeditable var isEnabled : Bool;
	default isEnabled = true;
	var isAvailable : Bool;
	default isAvailable = true;
}

class FollowSlotsComponent extends ScriptableComponent
{
	private const instanceeditable inlined var m_followSlots : array< FollowSlot >;

	public export function OnGameAttach()
	{
		var i : Int32;
		for( i = 0; i < m_followSlots.Size(); i += 1 )
		{
			m_followSlots[ i ].id = i;
		}
	}

	private function GetClosestAvailableSlot( requester : weak< GameObject > ) : FollowSlot
	{
		var availableSlots : array< Int32 >;
		var i : Int32;
		var closestSlot : FollowSlot;
		var requesterPosition : Vector4;
		availableSlots = GetAllAvailableSlots();
		closestSlot = m_followSlots[ availableSlots[ 0 ] ];
		requesterPosition = requester.GetWorldPosition();
		for( i = 0; i < availableSlots.Size(); i += 1 )
		{
			if( Vector4.Distance( requesterPosition, GetCurrentWorldPositionOfSlot( m_followSlots[ availableSlots[ i ] ] ) ) < Vector4.Distance( requesterPosition, GetCurrentWorldPositionOfSlot( closestSlot ) ) )
			{
				closestSlot = m_followSlots[ availableSlots[ i ] ];
			}
		}
		return closestSlot;
	}

	private function GetAllAvailableSlots() : array< Int32 >
	{
		var availableSlots : array< Int32 >;
		var i : Int32;
		for( i = 0; i < m_followSlots.Size(); i += 1 )
		{
			if( m_followSlots[ i ].isAvailable && m_followSlots[ i ].isEnabled )
			{
				availableSlots.PushBack( i );
			}
		}
		return availableSlots;
	}

	private function GetCurrentWorldPositionOfSlot( slot : FollowSlot ) : Vector4
	{
		var slotWorldOffsetFromVehicle : Vector4;
		var currentWorldPosition : Vector4;
		slotWorldOffsetFromVehicle = Vector4.RotByAngleXY( Transform.GetPosition( slot.slotTransform ), -1.0 * Vector4.Heading( GetOwner().GetWorldForward() ) );
		currentWorldPosition = GetOwner().GetWorldPosition() + slotWorldOffsetFromVehicle;
		return currentWorldPosition;
	}

	protected event OnReceiveSlotRequest( evt : RequestSlotEvent )
	{
		var allAvailableSlots : array< Int32 >;
		var availableSlot : FollowSlot;
		allAvailableSlots = GetAllAvailableSlots();
		if( allAvailableSlots.Size() > 0 )
		{
			availableSlot = GetClosestAvailableSlot( evt.requester );
			availableSlot.isAvailable = false;
			evt.blackboard.SetInt( GetAllBlackboardDefs().AIFollowSlot.slotID, availableSlot.id );
			evt.blackboard.SetVariant( GetAllBlackboardDefs().AIFollowSlot.slotTransform, availableSlot.slotTransform );
		}
	}

	protected event OnSlotReleased( evt : ReleaseSlotEvent )
	{
		m_followSlots[ evt.slotID ].isAvailable = true;
	}

}

class RequestSlotEvent extends Event
{
	var blackboard : weak< IBlackboard >;
	var requester : weak< GameObject >;
}

class ReleaseSlotEvent extends Event
{
	var slotID : Int32;
}

