namespace Zinnia.Tracking.Collision.Active.Operation
{
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using Zinnia.Extension;
///
/// Slices a selection of the collection from the given for the given and provides the sliced collection and the remaining collection separately.
///
public class Slicer : MonoBehaviour
{
#region Index Settings
[Header("Index Settings")]
[Tooltip("The zero-based index to start the slice at. A negative value counts backwards from the last index in the collection.")]
[SerializeField]
private int startIndex;
///
/// The zero-based index to start the slice at. A negative value counts backwards from the last index in the collection.
///
public int StartIndex
{
get
{
return startIndex;
}
set
{
startIndex = value;
}
}
[Tooltip("The number of elements in the slice.")]
[SerializeField]
private uint length = 1;
///
/// The number of elements in the slice.
///
public uint Length
{
get
{
return length;
}
set
{
length = value;
}
}
#endregion
#region State Events
///
/// Emitted when the Sliced list has changed since last slice.
///
[Header("State Events")]
public UnityEvent SlicedChanged = new UnityEvent();
///
/// Emitted when the Sliced list has remained unchanged since last slice.
///
public UnityEvent SlicedUnchanged = new UnityEvent();
///
/// Emitted when the Remained list has changed since last slice.
///
public UnityEvent RemainedChanged = new UnityEvent();
///
/// Emitted when the Remained list has remained unchanged since last slice.
///
public UnityEvent RemainedUnchanged = new UnityEvent();
#endregion
#region Data Events
///
/// Emitted when the sliced elements are taken from the collection.
///
[Header("Data Events")]
public ActiveCollisionsContainer.ActiveCollisionUnityEvent Sliced = new ActiveCollisionsContainer.ActiveCollisionUnityEvent();
///
/// Emitted when the remaining elements are left after slicing.
///
public ActiveCollisionsContainer.ActiveCollisionUnityEvent Remained = new ActiveCollisionsContainer.ActiveCollisionUnityEvent();
#endregion
///
/// The elements that have been sliced out of the list.
///
public ActiveCollisionsContainer.EventData SlicedList { get; protected set; } = new ActiveCollisionsContainer.EventData();
///
/// The elements that are still remaining in the list after a slice.
///
public ActiveCollisionsContainer.EventData RemainingList { get; protected set; } = new ActiveCollisionsContainer.EventData();
///
/// The cached list.
///
protected ActiveCollisionsContainer.EventData cachedSlicedList = new ActiveCollisionsContainer.EventData();
///
/// The cached list.
///
protected ActiveCollisionsContainer.EventData cachedRemainingList = new ActiveCollisionsContainer.EventData();
///
/// Slices the collision collection.
///
/// The original collision collection.
public virtual void DoSlice(ActiveCollisionsContainer.EventData originalList)
{
Slice(originalList);
}
///
/// Slices the collision collection.
///
/// The original collision collection.
/// The sliced collection.
public virtual ActiveCollisionsContainer.EventData Slice(ActiveCollisionsContainer.EventData originalList)
{
SlicedList.Clear();
RemainingList.Clear();
if (!this.CheckIsActiveAndEnabled())
{
return SlicedList;
}
CreateSlicedList(originalList);
CreateRemainedList(originalList);
return SlicedList;
}
///
/// Creates the contents of the sliced list.
///
/// The full list to slice.
protected virtual void CreateSlicedList(ActiveCollisionsContainer.EventData originalList)
{
int collectionCount = originalList.ActiveCollisions.Count;
int actualStartIndex = GetStartIndex(StartIndex, collectionCount);
int actualLength = GetRangeLength(actualStartIndex, (int)Length, collectionCount);
for (int index = actualStartIndex; index < actualStartIndex + actualLength; index++)
{
SlicedList.ActiveCollisions.Add(originalList.ActiveCollisions[index]);
}
if (!SlicedList.ActiveCollisions.SequenceEqual(cachedSlicedList.ActiveCollisions))
{
SlicedChanged?.Invoke();
}
else
{
SlicedUnchanged?.Invoke();
}
Sliced?.Invoke(SlicedList);
cachedSlicedList.ActiveCollisions = SlicedList.ActiveCollisions.GetRange(0, SlicedList.ActiveCollisions.Count);
}
///
/// Creates the contents of the remaining list.
///
/// The full list to slice.
protected virtual void CreateRemainedList(ActiveCollisionsContainer.EventData originalList)
{
foreach (CollisionNotifier.EventData originalCollision in originalList.ActiveCollisions)
{
if (!SlicedList.ActiveCollisions.Contains(originalCollision))
{
RemainingList.ActiveCollisions.Add(originalCollision);
}
}
if (!RemainingList.ActiveCollisions.SequenceEqual(cachedRemainingList.ActiveCollisions))
{
RemainedChanged?.Invoke();
}
else
{
RemainedUnchanged?.Invoke();
}
Remained?.Invoke(RemainingList);
cachedRemainingList.ActiveCollisions = RemainingList.ActiveCollisions.GetRange(0, RemainingList.ActiveCollisions.Count);
}
///
/// Slices the collision collection.
///
/// The original collision collection.
/// The collection of remaining elements that were not included in the sliced collection.
/// The sliced collection.
public virtual ActiveCollisionsContainer.EventData Slice(ActiveCollisionsContainer.EventData originalList, out ActiveCollisionsContainer.EventData remaining)
{
ActiveCollisionsContainer.EventData returnList = Slice(originalList);
remaining = (this.CheckIsActiveAndEnabled() ? RemainingList : originalList);
return returnList;
}
///
/// Gets the actual start index even if the index is a negative value.
///
/// The index to start from.
/// The total length of the entire collection
/// The actual start index to start from.
protected virtual int GetStartIndex(int checkIndex, int count)
{
return Mathf.Clamp(checkIndex < 0 ? count + checkIndex : checkIndex, 0, count);
}
///
/// Gets the actual valid length for the proposed range.
///
/// The index to start from.
/// The length of elements to return.
/// The total length of the entire collection
/// The actual valid length for the given range.
protected virtual int GetRangeLength(int checkIndex, int checkLength, int count)
{
int returnLength = checkLength;
int actualLength = checkIndex + checkLength;
if (actualLength >= count)
{
int offset = actualLength - count;
returnLength = checkLength - offset;
}
return returnLength;
}
}
}