using System;
using System.Collections.Generic;
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
/// types.
///
/// The type that is the value held by this
/// .
/// The type whose parent 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 child from ).
public class Parent : DynamicContainer
where TChild : class
where TParent : class
{
///
/// Initializes a new instance of the class.
///
/// The instance whose parent is being held by
/// this.
/// The method used to get the child
/// from a
/// type. This method will be used to add/remove the
/// to/from the parent children .
/// Thrown if
/// or is null.
public Parent(TChild child, Func> getChildren)
{
// Note: the value of this IValue is not provided in the constructor.
// This is because getChildren could return a "Children" type. The
// "Children" type will its own "getParent" method. If that method
// was invoked during the constructor of this object a crash would
// result because "getParent" would return null (since this parent
// hasn't been constructed).
child.ThrowIfNull("child");
getChildren.ThrowIfNull("getChildren");
_child = child;
_getChildren = getChildren;
Provide += OnProvide;
}
///
/// An event handler that is invoked when the parent has been changed.
///
/// The sender of the event.
/// The event arguments containg the old and new parent.
void OnProvide(object sender, ValueChangedEventArgs e)
{
if (e.OldValue != null)
_getChildren(e.OldValue).Remove(_child);
if (e.NewValue != null)
{
ICollection children = _getChildren(e.NewValue);
if(children.Contains(_child) == false)
children.Add(_child);
}
}
///
/// The instance whose parent is being held by this.
///
readonly TChild _child;
///
/// The method used to get the child from
/// a type.
///
readonly Func> _getChildren;
}
///
/// 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 HierarchalParent
: Parent where T : class, IHierarchal
{
///
/// Initializes a new instance of the
/// class.
///
/// The instance whose parent is being held by
/// this.
public HierarchalParent(T child)
: base(child, parent => parent.Children)
{}
}
}