/// <summary>Do a comparison to determine the relative order of <paramref name="aDescendant"/> and <paramref name="anotherDescendant"/></summary> /// <remarks>This method is invoked by the CompareTo method that implements IComparable for PartOfSpeechBuilder. Because this method is invoked /// on the most recent common ancestor of <paramref name="aDescendantPartOfSpeech"/> and <paramref name="anotherDescendantPartOfSpeech"/>, finding /// the ordering of those descendant parts of speech is equivalent to finding the ordering of the children of this common ancestor which are /// respective ancestors of those parts of speech.</remarks> public int CompareDescendants(IElementTreeNode aDescendant, IElementTreeNode anotherDescendant) { IElementTreeNode childAncestorOfADescendant = Children.Where(child => aDescendant.IsInSubtreeOf(child)).Single(); IElementTreeNode childAncestorOfAnotherDescendant = Children.Where(child => anotherDescendant.IsInSubtreeOf(child)).Single(); IElementTreeNode childToLookFor; // See if we can find a chain of ChildOrdering that connects aChild to anotherChild, in Before -> After order childToLookFor = childAncestorOfADescendant; do { ChildOrdering link = ChildOrderings.Where(ordering => ordering.Before == childToLookFor).FirstOrDefault(); if (link == null) // We're at the end of the chain and it didn't lead to what we're looking for { break; // Out of the do loop } else { if (link.After == childAncestorOfAnotherDescendant) { return(-1); // We found the chain we were looking for } else { childToLookFor = link.After; // Keep following the chain } } } while (true); // We failed to find a chain connecting aChild to anotherChild in Before -> After order. // Now we'll see if such a chain exists in After -> Before order childToLookFor = childAncestorOfADescendant; do { ChildOrdering link = ChildOrderings.Where(ordering => ordering.After == childToLookFor).FirstOrDefault(); if (link == null) // We're at the end of the chain and it didn't lead to what we're looking for { break; // Out of the do loop } else { if (link.Before == childAncestorOfAnotherDescendant) { return(1); // We found the chain we were looking for } else { childToLookFor = link.Before; // Keep following the chain } } } while (true); // We couldn't find a chain between these two IElementTreeNodes in either direction. // As far as this parent is concerned, they are equal. return(0); }
/// <summary>Remove any ChildOrderings that refer to <paramref name="child"/>.</summary> private protected void RemoveChildOrderingsThatReferTo(IElementTreeNode child) { ChildOrdering orderingWithTheRemovedChildAsBefore = ChildOrderings.FirstOrDefault(ordering => ordering.Before == child); ChildOrdering orderingWithTheRemovedChildAsAfter = ChildOrderings.FirstOrDefault(ordering => ordering.After == child); if (orderingWithTheRemovedChildAsBefore != null) { if (orderingWithTheRemovedChildAsAfter != null) // The removed child is between two other children { orderingWithTheRemovedChildAsBefore.Before = orderingWithTheRemovedChildAsAfter.Before; ChildOrderings.Remove(orderingWithTheRemovedChildAsAfter); } else { ChildOrderings.Remove(orderingWithTheRemovedChildAsBefore); // The removed child has no other children before it } } else { ChildOrderings.Remove(orderingWithTheRemovedChildAsAfter); // The removed child has no other children after it } }
/// <summary>Configure the ChildOrderings of this ParentElementBuilder so <paramref name="childToOrder"/> has relation <paramref name="relation"/> to <paramref name="childToOrderRelativeTo"/>.</summary> public void SetChildOrdering(IElementTreeNode childToOrder, IElementTreeNode childToOrderRelativeTo, NodeRelation relation) { switch (relation) { case NodeRelation.First: IElementTreeNode firstExistingChild = Children.OrderBy(child => child).FirstOrDefault(child => !ChildOrderings.Any(ordering => ordering.After == child)); if (firstExistingChild != null) { ChildOrderings.Add(new ChildOrdering { Before = childToOrder, After = firstExistingChild }); } break; case NodeRelation.Before: ChildOrdering existingOrderingBeforeRelativeChild = ChildOrderings.FirstOrDefault(ordering => ordering.After == childToOrderRelativeTo); if (existingOrderingBeforeRelativeChild != null) { ChildOrderings.Add(new ChildOrdering { Before = childToOrder, After = existingOrderingBeforeRelativeChild.After }); existingOrderingBeforeRelativeChild.After = childToOrder; } else { ChildOrderings.Add(new ChildOrdering { Before = childToOrder, After = childToOrderRelativeTo }); } break; case NodeRelation.After: ChildOrdering existingOrderingAfterRelativeChild = ChildOrderings.FirstOrDefault(ordering => ordering.Before == childToOrderRelativeTo); if (existingOrderingAfterRelativeChild != null) { ChildOrderings.Add(new ChildOrdering { Before = existingOrderingAfterRelativeChild.Before, After = childToOrder }); existingOrderingAfterRelativeChild.Before = childToOrder; } else { ChildOrderings.Add(new ChildOrdering { Before = childToOrderRelativeTo, After = childToOrder }); } break; case NodeRelation.Last: IElementTreeNode lastExistingChild = Children.OrderBy(child => child).FirstOrDefault(child => !ChildOrderings.Any(ordering => ordering.Before == child)); if (lastExistingChild != null) { ChildOrderings.Add(new ChildOrdering { Before = lastExistingChild, After = childToOrder }); } break; default: throw new ArgumentException("Unhandled relation type while trying to set ChildOrdering"); } }