/// <summary>
        /// Builds a filter starting at the node specified in <paramref name="path"/>
        /// including subfilters for parent and child nodes.
        /// </summary>
        /// <param name="path">The absolute path to the node from this node.</param>
        /// <returns></returns>
        public IFilter BuildFilter(FilterTreePath path)
        {
            //We won't add missing nodes to avoid polluting the tree.
            //The filter will still be created correctly because the 'missing' nodes
            //have a reference to the tree via their parent field and can therefore walk up correctly.
            RelationshipFilterTree node = FindNodeForPath(path, false);

            return(node.BuildChildAndParentFilters(null));
        }
        /// <summary>
        /// Creates a deep copy of this node and all child nodes and their properties.
        /// </summary>
        /// <param name="parent">The new parent node of the copied child nodes.</param>
        /// <returns></returns>
        protected RelationshipFilterTree DeepCopy(RelationshipFilterTree parent)
        {
            RelationshipFilterTree copy = new RelationshipFilterTree(_role, parent);

            copy._linkedIds = new HashSet <Guid>(_linkedIds);
            copy._filter    = _filter;
            foreach (var child in _children)
            {
                copy._children[child.Key] = child.Value.DeepCopy(copy);
            }
            return(copy);
        }
        /// <summary>
        /// Finds the node for the role specified in <paramref name="path"/>.
        /// </summary>
        /// <param name="path">The absolute path to the node from this node.</param>
        /// <param name="addMissingNodesToTree">Whether to add any missing nodes to the tree.</param>
        /// <returns></returns>
        protected RelationshipFilterTree FindNodeForPath(FilterTreePath path, bool addMissingNodesToTree)
        {
            RelationshipFilterTree node = this;

            if (path != null)
            {
                foreach (FilterTreePathSegment segment in path.Segments)
                {
                    node = node.FindChild(segment.Role, addMissingNodesToTree);
                }
            }
            return(node);
        }
        /// <summary>
        /// Finds the child node of this node with the role specified in <paramref name="role"/>.
        /// </summary>
        /// <param name="role">The role of the child node to find.</param>
        /// <param name="addMissingNodesToTree">Whether to add any missing nodes to the tree.</param>
        /// <returns></returns>
        protected RelationshipFilterTree FindChild(Guid role, bool addMissingNodesToTree)
        {
            RelationshipFilterTree node;

            if (!_children.TryGetValue(role, out node))
            {
                node = new RelationshipFilterTree(role, this);
                if (addMissingNodesToTree)
                {
                    _children[role] = node;
                }
            }
            return(node);
        }
 /// <summary>
 /// Constructs a node in an existing filter tree with the role specified in <paramref name="role"/>
 /// and parent specified in <paramref name="parent"/>.
 /// </summary>
 /// <param name="role">The role of this node.</param>
 /// <param name="parent">The parent of this node.</param>
 protected RelationshipFilterTree(Guid role, RelationshipFilterTree parent)
     : this(role)
 {
     _parent = parent;
 }
        /// <summary>
        /// Adds a linked id for the role specified in <paramref name="path"/>.
        /// The linked id will override any existing filters for the node.
        /// </summary>
        /// <param name="linkedId">The media item id to link to the node.</param>
        /// <param name="path">The absolute path to the node from this node.</param>
        public void AddLinkedId(Guid linkedId, FilterTreePath path)
        {
            RelationshipFilterTree node = FindNodeForPath(path, true);

            node.LinkedIds.Add(linkedId);
        }
        /// <summary>
        /// Adds a filter to the node specified in <paramref name="path"/>.
        /// </summary>
        /// <param name="filter">The filter to add. The filter will be combined with any existing filters for the node.</param>
        /// <param name="path">The absolute path to the node from this node.</param>
        public void AddFilter(IFilter filter, FilterTreePath path)
        {
            RelationshipFilterTree node = FindNodeForPath(path, true);

            node.CombineFilter(filter);
        }