/// <summary>
        /// Traverses the specified path, inserting <see cref="BranchNode"/>s as necessary, until the end of the path
        /// is reached, at which point the <paramref name="leafNodeProvider"/> is called to provide a leaf node to insert.
        /// </summary>
        protected void Insert(Path path, int pathDepth, Converter <PathSegment, ActionModelNode> leafNodeProvider)
        {
            int segmentCount = path.Segments.Count;

            if (segmentCount < 2)
            {
                throw new ArgumentException(SR.ExceptionInvalidActionPath);
            }

            PathSegment segment = path.Segments[pathDepth];

            if (pathDepth + 1 == segmentCount)
            {
                // this is the last path segment -> leaf node
                _childNodes.Add(leafNodeProvider(segment));
            }
            else
            {
                ActionModelNode child = FindChild(segment);
                if (child == null)
                {
                    child = new BranchNode(segment);
                    _childNodes.Add(child);
                }
                child.Insert(path, pathDepth + 1, leafNodeProvider);
            }
        }
        /// <summary>
        /// Creates a copy of the subtree beginning at this node.
        /// </summary>
        protected ActionModelNode CloneTree()
        {
            ActionModelNode clone = CloneNode(this.PathSegment);

            foreach (ActionModelNode child in _childNodes)
            {
                clone._childNodes.Add(child.CloneTree());
            }
            return(clone);
        }
        /// <summary>
        /// Persists an in-memory abstract action model to the XML model.
        /// </summary>
        /// <remarks>
        /// This method functions as a counterpart to <see cref="BuildAbstractActionModel"/>. The specified abstract action model
        /// (created by <see cref="BuildAbstractActionModel"/>, or potentially modified further) is flattened and its nodes
        /// written out to the XML mode, replacing any existing model at the same qualified site. This allows action model
        /// configuration interfaces to make changes to the action model.
        /// </remarks>
        /// <param name="namespace">A namespace to qualify the site.</param>
        /// <param name="site">The site.</param>
        /// <param name="abstractActionModel">The abstract action model to be persisted.</param>
        /// <returns>An <see cref="ActionModelNode"/> representing the root of the action model.</returns>
        public void PersistAbstractActionModel(string @namespace, string site, ActionModelRoot abstractActionModel)
        {
            // do one time initialization
            if (_actionModelXmlDoc == null)
            {
                Initialize();
            }

            XmlElement separatorTemplate = _actionModelXmlDoc.CreateElement("separator");

            string actionModelId = string.Format("{0}:{1}", @namespace, site);

            XmlElement xmlActionModel = FindXmlActionModel(actionModelId);

            if (xmlActionModel != null)
            {
                // clear the action model
                List <XmlNode> childrenToClear = CollectionUtils.Cast <XmlNode>(xmlActionModel.ChildNodes);
                foreach (XmlNode childNode in childrenToClear)
                {
                    xmlActionModel.RemoveChild(childNode);
                }
            }
            else
            {
                // add a new action model
                this.GetActionModelsNode().AppendChild(xmlActionModel = CreateXmlActionModel(actionModelId));
            }

            ActionModelNode[] leafNodes = abstractActionModel.GetLeafNodesInOrder();
            for (int n = 0; n < leafNodes.Length; n++)
            {
                ActionModelNode leafNode = leafNodes[n];
                if (leafNode is ActionNode)
                {
                    xmlActionModel.AppendChild(CreateXmlAction(_actionModelXmlDoc, ((ActionNode)leafNode).Action));
                }
                else if (leafNode is SeparatorNode)
                {
                    xmlActionModel.AppendChild(separatorTemplate.Clone());
                }
            }

            if (!_temporary)
            {
                this.ActionModelsXml = _actionModelXmlDoc;
                this.Save();
            }
        }
 /// <summary>
 /// Merges the specified model into this model.
 /// </summary>
 public void Merge(ActionModelNode other)
 {
     foreach (ActionModelNode otherChild in other._childNodes)
     {
         ActionModelNode thisChild = FindChild(otherChild.PathSegment);
         if (thisChild != null)
         {
             thisChild.Merge(otherChild);
         }
         else
         {
             _childNodes.Add(otherChild.CloneTree());
         }
     }
 }