/// <summary>
        /// Disseminates the changes to <paramref name="targetProduct"/>.
        /// </summary>
        /// <param name="targetProduct">The child form to which changes will be disseminated.</param>
        /// <param name="targetVariations">Control variations that exclude controls from dissemination.</param>
        public void Disseminate(ProductDefinition targetProduct, ProductVariation targetVariations)
        {
            foreach (PageDelta editedPageDelta in this.delta.EditedPages)
            {
                Page childPage = targetProduct.FormDefinition.Pages.FindByPageId(editedPageDelta.Revision.PageId);

                foreach (Control removed in editedPageDelta.RemovedControls)
                {
                    if (!targetVariations.UnlinkedControls.Contains(removed.Id))
                    {
                        childPage.Controls.RecursiveRemove(removed.Id);
                    }
                }

                foreach (Control control in editedPageDelta.SortedUpsertedControls)
                {
                    if (editedPageDelta.AddedControls.IndexOf(control) != -1)
                    {
                        int nextId = targetProduct.FormDefinition.Pages.GetNextControlId();
                        this.AddControl(control, childPage, targetVariations, nextId);
                    }
                    else if (editedPageDelta.EditedControls.IndexOf(control) != -1)
                    {
                        this.EditControl(control, childPage, targetVariations);
                    }
                }
            }

            int position = 1;
            foreach (Page p in targetProduct.FormDefinition.Pages)
            {
                foreach (Control c in p.Controls.Flatten())
                {
                    c.Position = position++;
                }
            }
        }
            private void GetTestObjects(string id, out ProductDisseminator disseminator, out ProductDefinition child, out ProductVariation variation)
            {
                string jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Parent-Original.json", id));
                ProductDefinition original = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Parent-Revision.json", id));
                ProductDefinition revision = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Child.json", id));
                child = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Child-Variation.json", id));
                variation = JsonConvert.DeserializeObject<ProductVariation>(jsonString);

                disseminator = new ProductDisseminator(original, revision);
            }
        /// <summary>
        /// Determines the correct position in the control tree of <paramref name="targetPage"/>
        /// and inserts <paramref name="control"/>.
        /// </summary>
        /// <param name="control">The control to add.</param>
        /// <param name="targetPage">The page to add control to.</param>
        /// <param name="targetVariations">The product variations.</param>
        /// <param name="nextId">The next available control id to be used in the case of a clash.</param>
        private void AddControl(Control control, Page targetPage, ProductVariation targetVariations, int nextId)
        {
            if (control.ParentId.HasValue && targetVariations.RemovedControls.Contains(control.ParentId.Value))
            {
                targetVariations.RemovedControls.Add(control.Id);
                return;
            }

            var addedIndex = targetVariations.AddedControls.IndexOf(control.Id);
            if (addedIndex != -1)
            {
                targetPage.Controls.FindRecursive(control.Id).Id = nextId;
                targetVariations.AddedControls[addedIndex] = nextId;
            }

            if (control.Type == ControlType.Group || control.Type == ControlType.Repeater)
            {
                ContainerControl container = control as ContainerControl;
                this.subControls.Add(control.Id, container.Controls);
                container.Controls = new ControlList();
            }

            this.InsertIntoList(control, targetPage, targetVariations.AddedControls);
        }
        /// <summary>
        /// Updates a linked control in <paramref name="targetPage"/> by <paramref name="control"/>.
        /// </summary>
        /// <param name="control">The control to add.</param>
        /// <param name="targetPage">The page to add control to.</param>
        /// <param name="targetVariations">The product variations.</param>
        private void EditControl(Control control, Page targetPage, ProductVariation targetVariations)
        {
            if (!targetVariations.UnlinkedControls.Contains(control.Id))
            {
                Control childControl = targetPage.Controls.FindRecursive(c => c.Id == control.Id);
                ControlList parent = childControl.GetParentControlList(targetPage.Controls);
                int index = parent.IndexOf(childControl);
                control = control.Clone();

                if (control.Type == ControlType.Group || control.Type == ControlType.Repeater)
                {
                    ContainerControl newContainerControl = control as ContainerControl;
                    ContainerControl oldContainerControl = parent[index] as ContainerControl;
                    newContainerControl.Controls = oldContainerControl.Controls;
                }

                if (childControl.ParentId != control.ParentId || childControl.Position != control.Position)
                {
                    if (control.ParentId.HasValue && targetVariations.RemovedControls.Contains(control.ParentId.Value))
                    {
                        targetVariations.EditedControls.Add(childControl.Id);
                        return;
                    }

                    targetPage.Controls.RecursiveRemove(control.Id);
                    childControl.ParentId = control.ParentId;
                    this.InsertIntoList(control, targetPage, targetVariations.AddedControls);
                }
                else
                {
                    parent[index] = control;
                }
            }
        }