using System;
using System.Collections.Generic;
using System.Linq;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Event;
using Chernobyl.Utility;
using Chernobyl.Values;
namespace Chernobyl.Collections.Generic.Hierarchy
{
///
/// A type that is used to maintain a parent-child relationship between two
/// objects.
///
/// The type whose children is held by this
/// . This type must be a reference type because a
/// value type would not work properly with this class (since you can't access
/// the parent from ).
/// The type that is the value held by this
/// .
public class Children : Collection
where TParent : class
{
///
/// Initializes a new instance of the
/// class.
///
/// The instance whose children is being held by
/// this.
/// A method that is able to get the parent of a
/// type. The argument passed to the
/// method is the child whose parent is to be returned.
/// Thrown if any of the parameters
/// provided are null.
public Children(TParent parent, Func> getParent)
: this(parent, getParent, new DecoratingEventList())
{}
///
/// Initializes a new instance of the
/// class.
///
/// The instance whose children is being held by
/// this.
/// The implementation of this
/// .
/// A method that is able to get the parent of a
/// type. The argument passed to the
/// method is the child whose parent is to be returned.
/// Thrown if any of the parameters
/// provided are null.
/// Thrown if items are contained
/// within .
public Children(TParent parent, Func> getParent, IEventCollection implementation)
{
parent.ThrowIfNull("parent");
getParent.ThrowIfNull("getParent");
implementation.ThrowIfNull("implementation");
if(implementation.Any())
throw new ArgumentException("The implementation provided cannot " +
"contain items.", "implementation");
_parent = parent;
_getParent = getParent;
_implementation = implementation;
_implementation.ItemsAdded += OnChildrenAdded;
_implementation.ItemsRemoved += OnChildrenRemoved;
}
///
/// An event handler that is should be invoked when the
/// type specified in the constructor
/// of this instance gains a new .
/// This method sets the parent of the instances specified in
/// .
///
/// The instance that generated the event.
/// The
/// instance containing the event data.
void OnChildrenAdded(object sender, ItemsEventArgs e)
{
foreach (TChild child in e.Items)
_getParent(child).Value = _parent;
}
///
/// An event handler that is invoked when
/// specified in the constructor of this instance loses a
/// . This method sets
/// the parent of the removed children (the instances specified in
/// ) to null if their parent is still set to
/// the instance provided in this
/// instances contructor.
///
/// The instance that generated the event.
/// The
/// instance containing the event data.
void OnChildrenRemoved(object sender, ItemsEventArgs e)
{
foreach (TChild child in e.Items)
{
IDynamicContainer parent = _getParent(child);
if (parent.Value == _parent)
parent.Value = null;
}
}
///
/// The implementation of this .
///
protected override ICollection Implementation
{
get { return _implementation; }
}
///
/// The instance whose children is being held by this.
///
readonly TParent _parent;
///
/// A method that is able to get the parent of a
/// type. The argument passed to the
/// method is the child whose parent is to be returned.
///
readonly Func> _getParent;
///
/// The backing field to .
///
readonly IEventCollection _implementation;
}
///
/// A type that is used to maintain a parent-child relationship between two
/// types. This type performs the same job as
/// but is easier to create for
/// types.
///
/// The reference type that
/// makes up the types contained in the hierarchy.
public class HierarchalChildren : Children where T : class, IHierarchal
{
///
/// Initializes a new instance of the class.
///
/// The instance whose children is being held by
/// this.
public HierarchalChildren(T parent)
: base(parent, child => child.Parent)
{}
}
}