using System; using System.Collections.Generic; using System.Linq; using Chernobyl.Collections.Generic.Event; using Chernobyl.Event; using Chernobyl.Utility; namespace Chernobyl.Collections.Generic { /// /// An that contains a set of random items /// from another . /// /// The type that is to be contained within this /// . public class Randoms : DecoratingEventEnumerable { /// /// Initializes a new instance of the class /// that allows duplicate values. /// /// The instance to choose the random items from. /// The number of random items to hold in this /// instance. This number must be above zero and will be clamped to the /// number of items in . public Randoms(IEventEnumerable enumerable, uint count) : this(enumerable, count, true, new Random(), new List()) { } /// /// Initializes a new instance of the class. /// /// The instance to choose the random items from. /// The number of random items to hold in this /// instance. If is true then this /// number will be clamped to the number of items in /// . This number must be above 0. /// True if duplicate random items can be /// contained in this instance, false if otherwise. public Randoms(IEventEnumerable enumerable, uint count, bool allowDuplicates) : this(enumerable, count, allowDuplicates, new Random(), new List()) {} /// /// Initializes a new instance of the class. /// /// The instance to choose the random items from. /// The number of random items to hold in this /// instance. If is true then this /// number will be clamped to the number of items in /// . This number must be above 0. /// True if duplicate random items can be /// contained in this instance, false if otherwise. /// The number generator /// to use when finding random items. /// The being /// decorated or extended with event capabilities. public Randoms(IEventEnumerable enumerable, uint count, bool allowDuplicates, Random random, ICollection collection) : base(collection) { enumerable.ThrowIfNull("enumerable"); if(count == 0) throw new ArgumentOutOfRangeException("count", count, "The count must be greater than zero."); random.ThrowIfNull("random"); collection.ThrowIfNull("collection"); _enumerable = enumerable; _items = collection; _count = count; _allowDuplicates = allowDuplicates; _random = random; Update(); _enumerable.ItemsAdded += (sender, e) => Update(); _enumerable.ItemsRemoved += (sender, e) => Update(); } /// /// Re-randomizes the items in this instance. /// void Update() { // Remove the old items. if (_items.Any()) { ItemsEventArgs eventArgs = new ItemsEventArgs(_items.ToList()); _items.Clear(); if (ItemsRemovedHandler != null) ItemsRemovedHandler(this, eventArgs); } // Add the new items. if (_enumerable.Any()) { _items.AddRange(_enumerable.Random(_count, _allowDuplicates, _random)); if (ItemsAddedHandler != null) ItemsAddedHandler(this, new ItemsEventArgs(_items)); } } /// /// The instance to choose the random items from. /// readonly IEventEnumerable _enumerable; /// /// The instance that stores the random items. /// readonly ICollection _items; /// /// The number of random items to hold in this instance. If /// is true then this number will be /// clamped to the number of items in . This /// number must be above 0. /// readonly uint _count; /// /// True if duplicate random items can be contained in this instance, /// false if otherwise. /// readonly bool _allowDuplicates; /// /// The number generator to use when finding random /// items. /// readonly Random _random; } /// /// Utility and extension code for /// and the client /// code that uses it. /// public static class RandomsExtensions { /// /// Creates an that contains a set of, /// continuously updated, random items from the /// specified. This method allows for /// duplicate items. /// /// The type that is to be contained within this /// . /// The instance to choose the random items from. /// The number of random items to hold in this /// instance. This number must be greater than 0 and will be clamped to /// . /// The containing the random /// items. public static IEventEnumerable Randoms(this IEventEnumerable enumerable, uint count) { return enumerable.Randoms(count, true); } /// /// Creates an that contains a set of, /// continuously updated, random items from the /// specified. /// /// The type that is to be contained within this /// . /// The instance to choose the random items from. /// The number of random items to hold in this /// instance. If is true then this /// number will be clamped to the number of items in /// . This number must be above 0. /// True if duplicate random items can be /// contained in this instance, false if otherwise. /// The containing the random /// items. public static IEventEnumerable Randoms(this IEventEnumerable enumerable, uint count, bool allowDuplicates) { return new Randoms(enumerable, count, allowDuplicates); } } }