namespace Fusion.Addons.KCC
{
	using System;
	using System.Collections.Generic;
	using UnityEngine;
	// This file contains implementation related to interactions - modifiers, collisions and processors.
	public partial class KCC
	{
		// PUBLIC METHODS
		/// 
		/// Check if the KCC has a collision with interaction provider of type T in KCCData.Collisions.
		/// 
		public bool HasCollision() where T : class
		{
			return Data.Collisions.HasProvider() == true;
		}
		/// 
		/// Check if the KCC has a collision with interaction provider in KCCData.Collisions.
		/// 
		/// IKCCInteractionProvider instance.
		public bool HasCollision(T provider) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			return Data.Collisions.HasProvider(provider) == true;
		}
		/// 
		/// Explicitly remove a collision (interaction provider) from KCCData.Collisions. Removed processor won't execute any pending stage method.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// IKCCInteractionProvider instance.
		/// Ignore result from IKCCInteractionProvider.CanStopInteraction() and force remove the collision. Be careful with this option.
		public bool RemoveCollision(T provider, bool forceRemove = false) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			KCCData data = Data;
			KCCCollision collision = data.Collisions.Find(provider);
			if (collision == null)
				return false;
			return RemoveCollision(data, collision, forceRemove);
		}
		/// 
		/// Check if the KCC has registered custom modifier (interaction provider) of type T in KCCData.Modifiers.
		/// 
		public bool HasModifier() where T : class
		{
			return Data.Modifiers.HasProvider() == true;
		}
		/// 
		/// Check if the KCC has registered custom modifier (interaction provider) in KCCData.Modifiers.
		/// 
		/// IKCCInteractionProvider instance.
		public bool HasModifier(T provider) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			return Data.Modifiers.HasProvider(provider) == true;
		}
		/// 
		/// Returns any registered custom modifier (interaction provider) of type T from KCCData.Modifiers.
		/// 
		public T GetModifier() where T : class
		{
			return Data.Modifiers.GetProvider();
		}
		/// 
		/// Returns all registered custom modifiers (interaction providers) of type T from KCCData.Modifiers.
		/// 
		/// List filled with interaction providers of type T.
		public void GetModifiers(List providers) where T : class
		{
			Data.Modifiers.GetProviders(providers, true);
		}
		/// 
		/// Returns all registered custom modifiers (interaction providers) of type T from KCCData.Modifiers.
		/// 
		public List GetModifiers() where T : class
		{
			List providers = new List();
			GetModifiers(providers);
			return providers;
		}
		/// 
		/// Register custom modifier (interaction provider) to KCCData.Modifiers.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// IKCCInteractionProvider instance.
		/// Ignore result from IKCCInteractionProvider.CanStartInteraction() and force add the modifier. Be careful with this option.
		public bool AddModifier(T provider, bool forceAdd = false) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			if (CheckSpawned() == false)
				return false;
			KCCData data = Data;
			if (data.Modifiers.HasProvider(provider) == true)
				return false;
			NetworkObject networkObject = provider.GetComponentNoAlloc();
			if (networkObject == null)
			{
				LogError($"Interaction provider {provider.name} doesn't have {nameof(NetworkObject)} component! Ignoring.", provider.gameObject);
				return false;
			}
			IKCCInteractionProvider checkProvider = provider.gameObject.GetComponentNoAlloc();
			if (object.ReferenceEquals(checkProvider, provider) == false)
			{
				LogError($"Object {provider.name} has multiple {nameof(IKCCInteractionProvider)} components, this is not allowed for custom modifiers! Ignoring.", provider.gameObject);
				return false;
			}
			if (forceAdd == false && provider.CanStartInteraction(this, data) == false)
				return false;
			KCCModifier modifier = data.Modifiers.Add(Runner, networkObject, provider);
			if (modifier.Processor != null)
			{
				OnProcessorAdded(data, modifier.Processor);
			}
			return true;
		}
		/// 
		/// Try to register custom modifier (interaction provider) to KCCData.Modifiers.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// IKCCInteractionProvider instance.
		/// Ignore result from IKCCInteractionProvider.CanStartInteraction() and force add the modifier. Be careful with this option.
		public bool TryAddModifier(IKCCInteractionProvider provider, bool forceAdd = false)
		{
			if (provider == null)
				return false;
			if (CheckSpawned() == false)
				return false;
			Component providerComponent = provider as Component;
			if (object.ReferenceEquals(providerComponent, null) == true)
				return false;
			KCCData data = Data;
			if (data.Modifiers.HasProvider(provider) == true)
				return false;
			NetworkObject networkObject = providerComponent.GetComponentNoAlloc();
			if (networkObject == null)
			{
				LogError($"Interaction provider {providerComponent.name} doesn't have {nameof(NetworkObject)} component! Ignoring.", providerComponent.gameObject);
				return false;
			}
			IKCCInteractionProvider checkProvider = providerComponent.gameObject.GetComponentNoAlloc();
			if (object.ReferenceEquals(checkProvider, provider) == false)
			{
				LogError($"Object {providerComponent.name} has multiple {nameof(IKCCInteractionProvider)} components, this is not allowed for custom modifiers! Ignoring.", providerComponent.gameObject);
				return false;
			}
			if (forceAdd == false && provider.CanStartInteraction(this, data) == false)
				return false;
			KCCModifier modifier = data.Modifiers.Add(Runner, networkObject, provider);
			if (modifier.Processor != null)
			{
				OnProcessorAdded(data, modifier.Processor);
			}
			return true;
		}
		/// 
		/// Try to register custom modifier (interaction provider) to KCCData.Modifiers if the network object has any.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// NetworkObject of the modifier.
		/// Ignore result from IKCCInteractionProvider.CanStartInteraction() and force add the modifier. Be careful with this option.
		public bool TryAddModifier(NetworkObject networkObject, bool forceAdd = false)
		{
			if (networkObject == null)
				return false;
			if (CheckSpawned() == false)
				return false;
			IKCCInteractionProvider provider = networkObject.GetComponentNoAlloc();
			if (provider == null)
				return false;
			KCCData data = Data;
			if (data.Modifiers.HasProvider(provider) == true)
				return false;
			if (forceAdd == false && provider.CanStartInteraction(this, data) == false)
				return false;
			KCCModifier modifier = data.Modifiers.Add(Runner, networkObject, provider);
			if (modifier.Processor != null)
			{
				OnProcessorAdded(data, modifier.Processor);
			}
			return true;
		}
		/// 
		/// Unregister custom modifier (interaction provider) from KCCData.Modifiers. Removed processor won't execute any pending stage method.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// IKCCInteractionProvider instance.
		/// Ignore result from IKCCInteractionProvider.CanStopInteraction() and force remove the modifier. Be careful with this option.
		public bool RemoveModifier(T provider, bool forceRemove = false) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			KCCData data = Data;
			KCCModifier modifier = data.Modifiers.Find(provider);
			if (modifier == null)
				return false;
			return RemoveModifier(data, modifier, forceRemove);
		}
		/// 
		/// Check if the KCC has registered any interaction provider of type T.
		/// 
		public bool HasInteraction() where T : class
		{
			KCCData data = Data;
			if (data.Modifiers.HasProvider() == true)
				return true;
			if (data.Collisions.HasProvider() == true)
				return true;
			return false;
		}
		/// 
		/// Check if the KCC has registered interaction provider.
		/// 
		/// IKCCInteractionProvider instance.
		public bool HasInteraction(T provider) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			KCCData data = Data;
			if (data.Modifiers.HasProvider(provider) == true)
				return true;
			if (data.Collisions.HasProvider(provider) == true)
				return true;
			return false;
		}
		/// 
		/// Returns any registered interaction provider of type T.
		/// 
		public T GetInteraction() where T : class
		{
			T provider;
			KCCData data = Data;
			provider = data.Modifiers.GetProvider();
			if (object.ReferenceEquals(provider, null) == false)
				return provider;
			provider = data.Collisions.GetProvider();
			if (object.ReferenceEquals(provider, null) == false)
				return provider;
			return null;
		}
		/// 
		/// Returns all registered interaction providers of type T.
		/// 
		/// List filled with interaction providers of type T.
		public void GetInteractions(List providers) where T : class
		{
			providers.Clear();
			KCCData data = Data;
			data.Modifiers.GetProviders(providers, false);
			data.Collisions.GetProviders(providers, false);
		}
		/// 
		/// Returns all registered interaction providers of type T.
		/// 
		public List GetInteractions() where T : class
		{
			List providers = new List();
			GetInteractions(providers);
			return providers;
		}
		/// 
		/// Unregister custom modifier (interaction provider) from KCCData.Modifiers or remove a collision from KCCData.Collisions. Removed processor won't execute any pending stage method.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// Interaction provider instance.
		/// Ignore result from IKCCInteractionProvider.CanStopInteraction() and force remove the interaction. Be careful with this option.
		public bool RemoveInteraction(T provider, bool forceRemove = false) where T : Component, IKCCInteractionProvider
		{
			if (provider == null)
				return false;
			bool removed = false;
			removed |= RemoveModifier(provider, forceRemove);
			removed |= RemoveCollision(provider, forceRemove);
			return removed;
		}
		/// 
		/// Check if the KCC interacts with any processor of type T.
		/// This method looks in modifiers, collisions, local and external processors.
		/// 
		public bool HasProcessor() where T : class
		{
			KCCData data = Data;
			if (data.Modifiers.HasProcessor() == true)
				return true;
			if (data.Collisions.HasProcessor() == true)
				return true;
			List localProcessors = _localProcessors;
			for (int i = 0, count = localProcessors.Count; i < count; ++i)
			{
				if (localProcessors[i] is T)
					return true;
			}
			if (GetExternalProcessors != null)
			{
				try
				{
					IList externalProcessors = GetExternalProcessors();
					if (externalProcessors != null && externalProcessors.Count > 0)
					{
						for (int i = 0, count = externalProcessors.Count; i < count; ++i)
						{
							if (externalProcessors[i] is T)
								return true;
						}
					}
				}
				catch (Exception exception)
				{
					UnityEngine.Debug.LogException(exception);
				}
			}
			return false;
		}
		/// 
		/// Check if the KCC interacts with a given processor.
		/// This method looks in modifiers, collisions, local and external processors.
		/// 
		/// IKCCProcessor instance.
		public bool HasProcessor(T processor) where T : Component, IKCCProcessor
		{
			if (processor == null)
				return false;
			KCCData data = Data;
			if (data.Modifiers.HasProcessor(processor) == true)
				return true;
			if (data.Collisions.HasProcessor(processor) == true)
				return true;
			List localProcessors = _localProcessors;
			for (int i = 0, count = localProcessors.Count; i < count; ++i)
			{
				if (object.ReferenceEquals(localProcessors[i], processor) == true)
					return true;
			}
			if (GetExternalProcessors != null)
			{
				try
				{
					IList externalProcessors = GetExternalProcessors();
					if (externalProcessors != null && externalProcessors.Count > 0)
					{
						for (int i = 0, count = externalProcessors.Count; i < count; ++i)
						{
							if (object.ReferenceEquals(externalProcessors[i], processor) == true)
								return true;
						}
					}
				}
				catch (Exception exception)
				{
					UnityEngine.Debug.LogException(exception);
				}
			}
			return false;
		}
		/// 
		/// Returns any interacting processor of type T.
		/// This method looks in modifiers, collisions, local and external processors.
		/// 
		public T GetProcessor() where T : class
		{
			T processor;
			KCCData data = Data;
			processor = data.Modifiers.GetProcessor();
			if (object.ReferenceEquals(processor, null) == false)
				return processor;
			processor = data.Collisions.GetProcessor();
			if (object.ReferenceEquals(processor, null) == false)
				return processor;
			List localProcessors = _localProcessors;
			for (int i = 0, count = localProcessors.Count; i < count; ++i)
			{
				if (localProcessors[i] is T localProcessor)
					return localProcessor;
			}
			if (GetExternalProcessors != null)
			{
				try
				{
					IList externalProcessors = GetExternalProcessors();
					if (externalProcessors != null && externalProcessors.Count > 0)
					{
						for (int i = 0, count = externalProcessors.Count; i < count; ++i)
						{
							if (externalProcessors[i] is T externalProcessor)
								return externalProcessor;
						}
					}
				}
				catch (Exception exception)
				{
					UnityEngine.Debug.LogException(exception);
				}
			}
			return null;
		}
		/// 
		/// Returns all interacting processors of type T.
		/// This method looks in modifiers, collisions, local and external processors.
		/// 
		/// List filled with processors of type T.
		/// Processors are sorted by processor priority. For stage sorting use KCCUtility.SortStages().
		public void GetProcessors(List processors, bool sortByProcessorPriority = false) where T : class
		{
			processors.Clear();
			KCCData data = Data;
			data.Modifiers.GetProcessors(processors, false);
			data.Collisions.GetProcessors(processors, false);
			List localProcessors = _localProcessors;
			for (int i = 0, count = localProcessors.Count; i < count; ++i)
			{
				if (localProcessors[i] is T localProcessor)
				{
					processors.Add(localProcessor);
				}
			}
			if (GetExternalProcessors != null)
			{
				try
				{
					IList externalProcessors = GetExternalProcessors();
					if (externalProcessors != null && externalProcessors.Count > 0)
					{
						for (int i = 0, count = externalProcessors.Count; i < count; ++i)
						{
							IKCCProcessor processor = externalProcessors[i];
							if (processor is T externalProcessor)
							{
								processors.Add(externalProcessor);
							}
						}
					}
				}
				catch (Exception exception)
				{
					UnityEngine.Debug.LogException(exception);
				}
			}
			if (sortByProcessorPriority == true)
			{
				KCCUtility.SortProcessors(this, processors);
			}
		}
		/// 
		/// Returns all interacting processors of type T.
		/// This method looks in modifiers, collisions, local and external processors.
		/// 
		/// Processors are sorted by processor priority. For stage sorting use KCCUtility.SortStages().
		public List GetProcessors(bool sortByProcessorPriority = false) where T : class
		{
			List processors = new List();
			GetProcessors(processors, sortByProcessorPriority);
			return processors;
		}
		/// 
		/// Register local processor to LocalProcessors list. Local processors are NOT networked, be careful!
		/// Note: KCCSettings.Processors are added as local processors upon initialization.
		/// 
		/// IKCCProcessor instance.
		public bool AddLocalProcessor(IKCCProcessor processor)
		{
			if (processor == null)
				throw new ArgumentNullException(nameof(processor));
			if (CheckSpawned() == false)
				return false;
			if (_localProcessors.Contains(processor) == true)
				return false;
			_localProcessors.Add(processor);
			try { processor.OnEnter(this, Data); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
			return true;
		}
		/// 
		/// Unregister local processor from LocalProcessors list. Local processors are NOT networked, be careful!
		/// 
		/// IKCCProcessor instance.
		public bool RemoveLocalProcessor(IKCCProcessor processor)
		{
			if (processor == null)
				return false;
			if (_localProcessors.Remove(processor) == false)
				return false;
			try { processor.OnExit(this, Data); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
			return true;
		}
		/// 
		/// Add/remove networked collider to/from custom ignore list. The object must have NetworkObject component to correctly synchronize over network.
		/// Changes done in render will vanish with next fixed update.
		/// 
		/// True if there is a change in the ignore list.
		public bool SetIgnoreCollider(Collider ignoreCollider, bool ignore)
		{
			if (ignoreCollider == null)
				return false;
			if (CheckSpawned() == false)
				return false;
			KCCData data = Data;
			if (ignore == true)
			{
				if (data.Ignores.HasCollider(ignoreCollider) == true)
					return false;
				NetworkObject networkObject = ignoreCollider.GetComponentNoAlloc();
				if (networkObject == null)
				{
					LogError($"Collider {ignoreCollider.name} doesn't have {nameof(NetworkObject)} component! Ignoring.", ignoreCollider.gameObject);
					return false;
				}
				Collider checkCollider = ignoreCollider.gameObject.GetComponentNoAlloc();
				if (object.ReferenceEquals(checkCollider, ignoreCollider) == false)
				{
					LogError($"Object {ignoreCollider.name} has multiple {nameof(Collider)} components, this is not allowed for ignored colliders! Ignoring.", ignoreCollider.gameObject);
					return false;
				}
				data.Ignores.Add(Runner, networkObject, ignoreCollider, false);
			}
			else
			{
				if (data.Ignores.Remove(ignoreCollider) == false)
					return false;
			}
			return true;
		}
		// PRIVATE METHODS
		private void UpdateCollisions(KCCData data, KCCOverlapInfo trackOverlapInfo)
		{
			int addCollisionsCount    = 0;
			int removeCollisionsCount = 0;
			List collisions = data.Collisions.All;
			for (int i = 0, count = collisions.Count; i < count; ++i)
			{
				KCCCollision collision = collisions[i];
				_removeColliders[removeCollisionsCount]  = collision.Collider;
				_removeCollisions[removeCollisionsCount] = collision;
				++removeCollisionsCount;
			}
			KCCOverlapHit[] trackHits = trackOverlapInfo.AllHits;
			for (int i = 0, count = trackOverlapInfo.AllHitCount; i < count; ++i)
			{
				Collider trackCollider      = trackHits[i].Collider;
				bool     trackColliderFound = false;
				for (int j = 0; j < removeCollisionsCount; ++j)
				{
					if (object.ReferenceEquals(_removeColliders[j], trackCollider) == true)
					{
						trackColliderFound = true;
						--removeCollisionsCount;
						_removeColliders[j]  = _removeColliders[removeCollisionsCount];
						_removeCollisions[j] = _removeCollisions[removeCollisionsCount];
						break;
					}
				}
				if (trackColliderFound == false)
				{
					_addColliders[addCollisionsCount] = trackCollider;
					++addCollisionsCount;
				}
			}
			for (int i = 0; i < removeCollisionsCount; ++i)
			{
				RemoveCollision(data, _removeCollisions[i], false);
			}
			for (int i = 0; i < addCollisionsCount; ++i)
			{
				AddCollision(data, _addColliders[i]);
			}
		}
		private bool AddCollision(KCCData data, Collider collisionCollider)
		{
			if (ReferenceEquals(collisionCollider, _lastNonNetworkedCollider) == true)
				return false;
			GameObject collisionObject = collisionCollider.gameObject;
			NetworkObject networkObject = collisionObject.GetComponentNoAlloc();
			if (networkObject == null)
			{
				_lastNonNetworkedCollider = collisionCollider;
				return false;
			}
			IKCCInteractionProvider interactionProvider = collisionObject.GetComponentNoAlloc();
			if (interactionProvider != null && interactionProvider.CanStartInteraction(this, data) == false)
				return false;
			KCCCollision collision = data.Collisions.Add(Runner, networkObject, interactionProvider, collisionCollider);
			if (collision.Processor != null)
			{
				OnProcessorAdded(data, collision.Processor);
			}
			if (OnCollisionEnter != null)
			{
				try { OnCollisionEnter(this, collision); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
			}
			return true;
		}
		private bool RemoveCollision(KCCData data, KCCCollision collision, bool forceRemove)
		{
			if (forceRemove == false)
			{
				IKCCInteractionProvider interactionProvider = collision.Provider;
				if (interactionProvider != null)
				{
					try
					{
						if (interactionProvider.CanStopInteraction(this, data) == false)
							return false;
					}
					catch (Exception exception)
					{
						UnityEngine.Debug.LogException(exception);
					}
				}
			}
			if (OnCollisionExit != null)
			{
				try { OnCollisionExit(this, collision); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
			}
			if (collision.Processor != null)
			{
				OnProcessorRemoved(data, collision.Processor);
			}
			data.Collisions.Remove(collision);
			return true;
		}
		private void ForceRemoveAllCollisions(KCCData data)
		{
			List collisions = data.Collisions.All;
			while (collisions.Count > 0)
			{
				RemoveCollision(data, collisions[collisions.Count - 1], true);
			}
		}
		private bool RemoveModifier(KCCData data, KCCModifier modifier, bool forceRemove)
		{
			if (forceRemove == false)
			{
				IKCCInteractionProvider interactionProvider = modifier.Provider;
				if (interactionProvider != null)
				{
					try
					{
						if (interactionProvider.CanStopInteraction(this, data) == false)
							return false;
					}
					catch (Exception exception)
					{
						UnityEngine.Debug.LogException(exception);
					}
				}
			}
			IKCCProcessor processor = modifier.Processor;
			if (data.Modifiers.Remove(modifier) == true)
			{
				if (processor != null)
				{
					OnProcessorRemoved(data, processor);
				}
			}
			return true;
		}
		private void ForceRemoveAllModifiers(KCCData data)
		{
			List modifiers = data.Modifiers.All;
			while (modifiers.Count > 0)
			{
				RemoveModifier(data, modifiers[modifiers.Count - 1], true);
			}
		}
		private void OnProcessorAdded(KCCData data, IKCCProcessor processor)
		{
			try { processor.OnEnter(this, data); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
		}
		private void OnProcessorRemoved(KCCData data, IKCCProcessor processor)
		{
			for (int j = 0, stageCount = _activeStages.Count; j < stageCount; ++j)
			{
				KCCStageInfo    activeStageInfo       = _activeStages[j];
				IKCCProcessor[] activeStageProcessors = activeStageInfo.Processors;
				for (int i = 0, count = activeStageInfo.ProcessorCount; i < count; ++i)
				{
					if (ReferenceEquals(activeStageProcessors[i], processor) == true)
					{
						activeStageProcessors[i] = null;
						break;
					}
				}
			}
			if (_cachedProcessorCount > 0)
			{
				IKCCProcessor[] cachedProcessors = _cachedProcessors;
				for (int i = 0, count = _cachedProcessorCount; i < count; ++i)
				{
					if (ReferenceEquals(cachedProcessors[i], processor) == true)
					{
						cachedProcessors[i] = null;
						break;
					}
				}
			}
			if (_stageProcessorCount > 0)
			{
				IKCCProcessor[] stageProcessors = _stageProcessors;
				for (int i = 0, count = _stageProcessorCount; i < count; ++i)
				{
					if (ReferenceEquals(stageProcessors[i], processor) == true)
					{
						stageProcessors[i] = null;
						break;
					}
				}
			}
			try { processor.OnExit(this, data); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); }
		}
		private void CacheProcessors(KCCData data)
		{
			_cachedProcessorCount = 0;
			List modifiers = data.Modifiers.All;
			for (int i = 0, count = modifiers.Count; i < count; ++i)
			{
				KCCUtility.AddUniqueProcessor(this, modifiers[i].Processor, _cachedProcessors, ref _cachedProcessorCount);
			}
			List collisions = data.Collisions.All;
			for (int i = 0, count = collisions.Count; i < count; ++i)
			{
				KCCUtility.AddUniqueProcessor(this, collisions[i].Processor, _cachedProcessors, ref _cachedProcessorCount);
			}
			List localProcessors = _localProcessors;
			for (int i = 0, count = localProcessors.Count; i < count; ++i)
			{
				KCCUtility.AddUniqueProcessor(this, localProcessors[i], _cachedProcessors, ref _cachedProcessorCount);
			}
			if (GetExternalProcessors != null)
			{
				try
				{
					IList externalProcessors = GetExternalProcessors();
					if (externalProcessors != null && externalProcessors.Count > 0)
					{
						for (int i = 0, count = externalProcessors.Count; i < count; ++i)
						{
							KCCUtility.AddUniqueProcessor(this, externalProcessors[i], _cachedProcessors, ref _cachedProcessorCount);
						}
					}
				}
				catch (Exception exception)
				{
					UnityEngine.Debug.LogException(exception);
				}
			}
			KCCUtility.SortProcessors(this, _cachedProcessors, _cachedProcessorCount);
			_stageProcessorCount = _cachedProcessorCount;
			if (_stageProcessorCount > 0)
			{
				Array.Copy(_cachedProcessors, _stageProcessors, _stageProcessorCount);
			}
		}
	}
}