/// <summary>
        /// Save displayed order
        /// </summary>
        public void apply()
        {
            answersResult = new answers();

            saveNodes(root.Nodes, answersResult.Items);

            string result = answersResult.Serialize();
            log.Debug(result);

            CustomXmlUtilities.replaceXmlDoc(answersPart, result);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="target"></param>
        /// <param name="setSourceAttr">When saving a building block, we want to write the ID of the source part</param>
        /// <param name="setBindingStore">When re-using a building block, storeItemID to write to the xpath; otherwise null</param>
        /// <param name="overwriteExisting">If re-using a building block back into original source, we want to skip silently.
        /// When going the other way, we want to overwrite the logic in any existing building block (since
        /// it may have been updated).</param>
        public void injectLogic(Model targetModel, bool setSourceAttr, bool setBindingStore, bool overwriteExisting)
        {
            //Model targetModel = Model.ModelFactory(target);

            // XPaths
            XPathsPartEntry targetXppe = new XPathsPartEntry(targetModel);
            string sourceAttr = null;
            if (setSourceAttr)
            {
                sourceAttr = srcXPathsPart.Id;
            }
            string answersPartStoreID = null;
            if (setBindingStore)
            {
                answersPartStoreID = targetModel.answersPart.Id;
            }

            // .. add em
            foreach (xpathsXpath xp in BBxpaths)
            {
                xpathsXpath existing = targetXppe.getXPathByID(xp.id);
                if (existing == null)
                {
                    injectLogicXPath(targetXppe, xp, sourceAttr, answersPartStoreID);
                } else
                {
                    // Does it come from this doc?
                    //log.Debug("xp.source: " + xp.source);
                    //log.Debug("existing.source: " + existing.source);
                    //log.Debug("targetModel.xpathsPart.Id: " + targetModel.xpathsPart.Id);
                    if (xp.source != null && xp.source.Equals(targetModel.xpathsPart.Id))
                    {
                        // yes ..
                        if (overwriteExisting)
                        {
                            injectLogicXPath(targetXppe, xp, sourceAttr, answersPartStoreID);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (xp.source != null &&
                        existing.source != null &&
                        xp.source.Equals(existing.source))
                    {
                        // It has already been copied in.
                        // so don't do it again, whether we're copying to template
                        // (could go either way, but for now, only update from original source),
                        // or into docx
                        continue;

                    } else
                    {
                        // Yikes! ID collision
                        throw new BuildingBlockLogicException("XPath with ID " + xp.id + " is already present.");
                    }
                }
            }

            // Questions
            questionnaire targetQuestionnaire = new questionnaire();
            questionnaire.Deserialize(targetModel.questionsPart.XML, out targetQuestionnaire);
            // .. add em
            foreach (question q in BBquestions)
            {
                question existing = targetQuestionnaire.getQuestion(q.id);
                if (existing == null)
                {
                    targetQuestionnaire.questions.Add(q);
                    if (setSourceAttr)
                    {
                        q.source = srcQuestionsPart.Id;
                    }
                }
                else
                {
                    // Does it come from this doc?
                    //log.Debug("q.source: " + q.source);
                    //log.Debug("existing.source: " + existing.source);
                    //log.Debug("targetModel.questionsPart.Id: " + targetModel.questionsPart.Id);
                    if (q.source != null && q.source.Equals(targetModel.questionsPart.Id))
                    {
                        // yes ..
                        if (overwriteExisting)
                        {
                            targetQuestionnaire.questions.Add(q); // this is a HashSet, so we're overrwriting, not adding :-)
                            if (setSourceAttr)
                            {
                                q.source = targetModel.questionsPart.Id;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (q.source != null &&
                        existing.source != null &&
                        q.source.Equals(existing.source))
                    {
                        // It has already been copied in.
                        continue;
                    }
                    else
                    {
                        // Yikes! ID collision
                        throw new BuildingBlockLogicException("Question with ID " + q.id + " is already present.");
                    }
                }
            }

            // Answers
            answers targetAnswers = new answers();
            answers.Deserialize(targetModel.answersPart.XML, out targetAnswers);
            foreach (answer a in BBanswers)
            {
                answer existing = getAnswer(targetAnswers, a.id);
                if (existing == null)
                {
                    targetAnswers.Items.Add(a);
                    if (setSourceAttr)
                    {
                        a.source = srcAnswersPart.Id;
                    }
                }
                else
                {
                    // Does it come from this doc?
                    if (a.source != null && a.source.Equals(targetModel.answersPart.Id))
                    {
                        log.Debug("source is this part");
                        // yes ..
                        if (overwriteExisting)
                        {
                            log.Debug(".. and overwriting..");
                            targetAnswers.Items.Add(a); // this is a HashSet, so we're overrwriting, not adding :-)
                            if (setSourceAttr)
                            {
                                a.source = srcAnswersPart.Id;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (a.source != null &&
                        existing.source != null &&
                        a.source.Equals(existing.source))
                    {
                        // It has already been copied in.
                        log.Debug("this logic already present");
                        continue;
                    }
                    else
                    {
                        // Yikes! ID collision
                        throw new BuildingBlockLogicException("Answer with ID " + a.id + " from different source is already present.");
                    }
                }
            }
            foreach (repeat r in BBrepeats)
            {
                repeat existing = getRepeat(targetAnswers, r.qref);
                if (existing == null)
                {
                    targetAnswers.Items.Add(r);
                    if (setSourceAttr)
                    {
                        r.source = srcAnswersPart.Id;
                    }
                }
                else
                {
                    // Does it come from this doc?
                    if (r.source != null && r.source.Equals(targetModel.answersPart.Id))
                    {
                        // yes ..
                        if (overwriteExisting)
                        {
                            targetAnswers.Items.Add(r); // this is a HashSet, so we're overrwriting, not adding :-)
                            if (setSourceAttr)
                            {
                                r.source = srcAnswersPart.Id;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (r.source != null &&
                        existing.source != null &&
                        r.source.Equals(existing.source))
                    {
                        // It has already been copied in.
                        continue;
                    }
                    else
                    {
                        // Yikes! ID collision
                        throw new BuildingBlockLogicException("Answer with ID " + r.qref + " is already present.");
                    }
                }
            }

            // Conditions
            conditions targetConditions = new conditions();
            conditions.Deserialize(targetModel.conditionsPart.XML, out targetConditions);
            foreach (condition c in BBconditions)
            {
                condition existing = getCondition(targetConditions, c.id);
                if (existing == null)
                {
                    targetConditions.condition.Add(c);
                    if (setSourceAttr)
                    {
                        c.source = srcConditionsPart.Id;
                    }
                }
                else
                {
                    // Does it come from this doc?
                    if (c.source != null && c.source.Equals(targetModel.conditionsPart.Id))
                    {
                        // yes ..
                        if (overwriteExisting)
                        {
                            targetConditions.condition.Add(c);  // this is a HashSet, so we're overrwriting, not adding :-)
                            if (setSourceAttr)
                            {
                                c.source = targetModel.conditionsPart.Id;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (c.source != null &&
                        existing.source != null &&
                        c.source.Equals(existing.source))
                    {
                        // It has already been copied in.
                        continue;
                    }
                    else
                    {
                        // Yikes! ID collision
                        throw new BuildingBlockLogicException("Condition with ID " + c.id + " is already present.");
                    }
                }
            }

            // .. save: we only save if there have been no ID collisions.
            // Otherwise, we will have aborted with a BuildingBlockLogicException
            targetXppe.save();
            CustomXmlUtilities.replaceXmlDoc(targetModel.questionsPart, targetQuestionnaire.Serialize());
            CustomXmlUtilities.replaceXmlDoc(targetModel.conditionsPart, targetConditions.Serialize());
            CustomXmlUtilities.replaceXmlDoc(targetModel.answersPart, targetAnswers.Serialize());
        }