using Newtonsoft.Json; using RhythmBase.Events; using System.Collections; namespace RhythmBase.Components { /// /// A collection of events that maintains the sequence of events. /// public abstract class OrderedEventCollection : ICollection { /// /// Gets the total count of events in the collection. /// [JsonIgnore] public virtual int Count => eventsBeatOrder.Sum((i) => i.Value.Count()); /// /// Gets a value indicating whether the collection is read-only. /// [JsonIgnore] public bool IsReadOnly { get; } /// /// Returns the beat of the last event. /// /// The beat of the last event. [JsonIgnore] public RDBeat Length => eventsBeatOrder.LastOrDefault().Value.FirstOrDefault()?.Beat??new(); /// /// Initializes a new instance of the class. /// public OrderedEventCollection() { eventsBeatOrder = []; IsReadOnly = false; } /// /// Initializes a new instance of the class with the specified items. /// /// The items to add to the collection. public OrderedEventCollection(IEnumerable items) { eventsBeatOrder = []; IsReadOnly = false; foreach (IBaseEvent item in items) Add(item); } /// /// Concatenates all events in the collection. /// /// A list of all events in the collection. public IEnumerable ConcatAll() => eventsBeatOrder.SelectMany(i => i.Value).ToList(); /// /// Adds an event to the collection. /// /// The event to add. public void Add(IBaseEvent item) { TypedEventCollection list = []; if (eventsBeatOrder.TryGetValue(item.Beat, out TypedEventCollection? value)) list = value; else eventsBeatOrder.Add(item.Beat, list); list.Add(item); } /// /// Clears all events from the collection. /// public void Clear() => eventsBeatOrder.Clear(); /// /// Determines whether the collection contains a specific event. /// /// The event to locate in the collection. /// true if the event is found in the collection; otherwise, false. public virtual bool Contains(IBaseEvent item) => eventsBeatOrder.ContainsKey(item.Beat) && eventsBeatOrder[item.Beat].Contains(item); /// /// Copies the elements of the collection to an array, starting at a particular array index. /// /// The array to copy the elements to. /// The zero-based index in the array at which copying begins. public void CopyTo(IBaseEvent[] array, int arrayIndex) { ArgumentNullException.ThrowIfNull(array); if (arrayIndex < 0 || arrayIndex > array.Length) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); if (array.Length - arrayIndex < Count) throw new ArgumentException("The number of elements in the source collection is greater than the available space from arrayIndex to the end of the destination array."); foreach (var pair in eventsBeatOrder) { foreach (var item in pair.Value) { array[arrayIndex++] = item; } } } /// /// Removes the first occurrence of a specific event from the collection. /// /// The event to remove from the collection. /// true if the event was successfully removed; otherwise, false. internal bool Remove(IBaseEvent item) { bool Remove; if (Contains(item)) { bool result = eventsBeatOrder[item.Beat].Remove(item); if (!eventsBeatOrder[item.Beat].Any()) eventsBeatOrder.Remove(item.Beat); Remove = result; } else Remove = false; return Remove; } /// /// Returns an enumerator that iterates through the collection. /// /// An enumerator for the collection. public IEnumerator GetEnumerator() { foreach (KeyValuePair> pair in eventsBeatOrder) foreach (IBaseEvent item in pair.Value) yield return item; } /// /// Returns an enumerator that iterates through the collection. /// /// An enumerator for the collection. IEnumerator IEnumerable.GetEnumerator() { foreach (KeyValuePair> pair in eventsBeatOrder) foreach (IBaseEvent item in pair.Value) yield return item; } /// /// Returns a string that represents the current object. /// /// A string that represents the current object. public override string ToString() => string.Format("Count = {0}", Count); /// /// Removes the first occurrence of a specific event from the collection. /// /// The event to remove from the collection. /// true if the event was successfully removed; otherwise, false. bool ICollection.Remove(IBaseEvent item) => throw new NotImplementedException(); /// /// The dictionary that maintains the order of events based on their beats. /// internal SortedDictionary> eventsBeatOrder; } }