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);
}
}
}