/// <summary> /// Inserts a <see cref="Message"/> as the first child of a parent message. /// </summary> /// <remarks> /// <para> /// The child's <see cref="Parent"/> field will be set to this message, /// as will that of its predecessors. /// </para> /// <para> /// If this message already has a child, the existing child will be appended /// as the "oldest" predecessor of the new child. <seealso cref="AddOldestPredecessor"/> /// </para> /// </remarks> /// <param name="newFirstChild">The child to insert.</param> public void InsertChild(Message newFirstChild) { if (newFirstChild.Parent != null) { throw new ArgumentException("A child Message cannot be inserted if it already has a parent Message.", "newFirstChild"); } // Preserve the existing child. Message existing = this.Child; // Set the new first child and update its Parent references. this.Child = newFirstChild; for (Message sibling = newFirstChild; sibling != null; sibling = sibling.Predecessor) { sibling.Parent = this; } // Preserve the existing child (after the call to SetChildAndUpdateParents // because its Parent reference should already point to this message. newFirstChild.AddOldestPredecessor(existing); }
/// <summary> /// Attempts to combine two forrests of messages. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual void ZipInto(ref Message other) { if (this == other) { throw new ArgumentException("A message cannot be zipped into itself.", "other"); } else if (other == null) { other = this; return; } else if (this.TargetId.Equals(other.TargetId)) { if (this.Parent != other.Parent && this.Parent != null && other.Parent != null) { throw new ArgumentException("Two child messages cannot be zipped if they have different parents.", "other"); } // Attempt to copy this message's information into the other one. MergeAction result = this.MergeInto(other); switch (result) { case MergeAction.KeepBothInOrder: // The default action: Insert this message chronologically after the other, // and keep all children and information separately from both messages. // (This is the same as if the messages were unrelated, below.) this.AddOldestPredecessor(other); other = this; break; case MergeAction.DiscardOther: // The information in this packet completely replaces that in the other. // The other packet is now useless, so we steal its predecessors. this.AddOldestPredecessor(other.Predecessor); other.Predecessor = null; // We can also recursively merge the children, being careful to copy // from this message into the other to preserve chronological order. this.ZipChildrenInto(other); // Then move the children back to be children of this message. // Disconnect the new children's parent first so InsertChild doesn't complain. if (other.Child != null) { for (Message child = other.Child; child != null; child = child.Predecessor) { child.Parent = null; } this.InsertChild(other.Child); other.Child = null; } // Having copied all children, predecessors, and information, // replace the useless message with this one. other = this; break; case MergeAction.DiscardThis: // The information in the other packet is "better" than in this packet, // or the subclass has copied all relavent information to the other. // This packet is now useless. We can also recursively merge the children. other.AddOldestPredecessor(this.Predecessor); this.Predecessor = null; this.ZipChildrenInto(other); break; default: throw new ArgumentException("Invalid MergedAction value returned by MergeInto."); } } else { // If the messages are unrelated, simply arrange them in chronological order, // and keep all children and information separately from both messages. // (This is the same as MergeAction.KeepBothInOrder, above.) this.AddOldestPredecessor(other); other = this; } }