/// <summary>
        /// Inserts the specified element immediately before the specified reference element.
        /// </summary>
        /// <param name="newChild">The OpenXmlElement to insert.</param>
        /// <param name="refChild">The OpenXmlElement that is in the reference node.</param>
        /// <returns>The OpenXmlElement that was inserted.</returns>
        /// <remarks>Returns null if newChild equals null.</remarks>
        public override T InsertBefore <T>(T newChild, OpenXmlElement refChild)
        {
            if (newChild == null)
            {
                // throw new ArgumentNullException(nameof(newChild));
                return(null);
            }

            if (newChild.Parent != null)
            {
                throw new InvalidOperationException(ExceptionMessages.ElementIsPartOfTree);
            }

            if (refChild == null)
            {
                return(AppendChild(newChild));
            }

            if (refChild != null && refChild.Parent != this)
            {
                throw new InvalidOperationException();
            }

            ElementInsertingEvent(newChild);

            OpenXmlElement prevNode = newChild;
            OpenXmlElement nextNode = refChild;

            Debug.Assert(nextNode != null);
            Debug.Assert(prevNode != null);

            if (nextNode == FirstChild)
            {
                prevNode.next   = nextNode;
                _lastChild.next = prevNode;
            }
            else
            {
                OpenXmlElement previousSibling = nextNode.PreviousSibling();
                prevNode.next        = nextNode;
                previousSibling.next = prevNode;
            }

            newChild.Parent = this;
            // SetOwner(newChild);

            ElementInsertedEvent(newChild);

            return(newChild);
        }
        private protected void SetElement <T>(int sequenceNumber, T newChild)
            where T : OpenXmlElement
        {
            switch (OpenXmlCompositeType)
            {
            case OpenXmlCompositeType.Other:
                throw new InvalidOperationException();

            case OpenXmlCompositeType.OneAll:
            {
                T child = GetElement <T>(sequenceNumber);
                if (child != null)
                {
                    // remove the old one
                    RemoveChild(child);
                }

                if (newChild != null)
                {
                    AppendChild(newChild);
                }
            }

                // TODO: should we handle error case?
                //  1: there are more than 1 elements for a type?
                //  2: there are more than 2 elements?
                //  3. there are other elements other than allowed children?
                break;

            case OpenXmlCompositeType.OneChoice:
            {
                OpenXmlElement child         = FirstChild;
                OpenXmlElement previousChild = null;

                // skip unknown element and MiscNode
                while (child != null && !IsKnownElement(child))
                {
                    previousChild = child;
                    child         = child.NextSibling();
                }

                OpenXmlElement next = null;
                while (child != null)
                {
                    next = child.NextSibling();

                    // remove all exist elements
                    if (IsKnownElement(child))
                    {
                        RemoveChild(child);
                    }

                    child = next;
                }

                if (newChild != null)
                {
                    InsertAfter(newChild, previousChild);
                }
            }

                // TODO: should we handle error case?
                //  1: there are more than 1 elements for a type?
                //  2: there are more than 2 elements?
                //  3. there are other elements other than allowed children?
                break;

            case OpenXmlCompositeType.OneSequence:
            {
                OpenXmlElement child = FirstChild;
                OpenXmlElement prev  = null;

                while (child != null)
                {
                    if (IsKnownElement(child))
                    {
                        int childSequenceNumber = GetSequenceNumber(child);

                        if (childSequenceNumber == sequenceNumber)
                        {
                            // remove the old one
                            if (child is T)
                            {
                                // insert the new element after the previous.
                                prev = child.PreviousSibling();
                                RemoveChild(child);
                                break;
                            }
                            else
                            {
                                // same tag name, but wrong type, see bug 448241
                                prev = child;
                            }
                        }
                        else if (childSequenceNumber > sequenceNumber)
                        {
                            break;
                        }
                        else
                        {
                            // always insert after the first known element
                            prev = child;

                            // continue search
                        }
                    }

                    // continue search
                    child = child.NextSibling();
                }

                if (newChild != null)
                {
                    InsertAfter(newChild, prev);
                }
            }

                // TODO: should we handle error case?
                //  1: there are more than 1 elements for a type?
                //  2: there are more than 2 elements?
                //  3. there are other elements other than allowed children?
                break;
            }
        }