/// <summary>
        ///
        /// </summary>
        private void CollectCategories()
        {
            try
            {
                //Categories that have material quantities
                var collector         = new FilteredElementCollector(LinkedDocument);
                var elements          = collector.WhereElementIsNotElementType().ToElements().ToList();
                var elementCategories = from element in elements where null != element.Category select element.Category;
                var modelCategories   = from category in elementCategories where  category.HasMaterialQuantities && category.CategoryType == CategoryType.Model select category;

                var categoryNames    = from category in modelCategories select category.Name;
                var categoryNameList = categoryNames.Distinct().ToList();

                var categoryObjects = LinkedDocument.Settings.Categories;
                foreach (var catName in categoryNameList)
                {
                    if (!categoryObjects.Contains(catName))
                    {
                        continue;
                    }

                    var category = categoryObjects.get_Item(catName);
                    if (null != category)
                    {
                        var catProperties = new CategoryProperties(category);
                        var categoryFound = from modelCat in modelCategories where modelCat.Id == category.Id select modelCat;
                        var itemCount     = categoryFound.Count();
                        if (itemCount > 0)
                        {
                            catProperties.ItemCount = itemCount;
                            if (!Categories.ContainsKey(catProperties.CategoryId))
                            {
                                Categories.Add(catProperties.CategoryId, catProperties);
                            }
                        }
                    }
                }

                //Categories that belongs to MEP curves
                collector = new FilteredElementCollector(LinkedDocument);
                var mepCurves = collector.OfClass(typeof(MEPCurve)).ToElements().ToList();
                if (mepCurves.Count > 0)
                {
                    var mepCategories       = from mepCurve in mepCurves select mepCurve.Category.Name;
                    var mepCategoryNameList = mepCategories.Distinct().ToList();
                    foreach (var catName in mepCategoryNameList)
                    {
                        if (!categoryObjects.Contains(catName))
                        {
                            continue;
                        }

                        var category = categoryObjects.get_Item(catName);
                        if (null != category)
                        {
                            var catProperties = new CategoryProperties(category);
                            var categoryFound = from mepCurve in mepCurves where mepCurve.Category.Id == category.Id select mepCurve;
                            var itemCount     = categoryFound.Count();
                            if (itemCount > 0)
                            {
                                catProperties.ItemCount = itemCount;
                                if (!Categories.ContainsKey(catProperties.CategoryId))
                                {
                                    Categories.Add(catProperties.CategoryId, catProperties);
                                }
                            }
                        }
                    }
                }

                foreach (var bltCategory in customCategories)
                {
                    var catPriority = 0;
                    if (bltCategory == BuiltInCategory.OST_Rooms)
                    {
                        catPriority = 2;
                    }

                    collector = new FilteredElementCollector(LinkedDocument);
                    var customCatElements = collector.OfCategory(bltCategory).ToElementIds();
                    if (customCatElements.Count > 0)
                    {
                        var category = categoryObjects.get_Item(bltCategory);
                        if (null != category)
                        {
                            var catProperties = new CategoryProperties(category);
                            catProperties.Priority  = catPriority;
                            catProperties.ItemCount = customCatElements.Count;
                            if (!Categories.ContainsKey(catProperties.CategoryId))
                            {
                                Categories.Add(catProperties.CategoryId, catProperties);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                var message = ex.Message;
            }
        }
        private static LinkedInstanceProperties DuplicateElements(Document recipientDoc, LinkedInstanceProperties lip, CategoryProperties cp, UpdateMode updateMode)
        {
            var updatedLIP = lip;

            try
            {
                var collector      = new FilteredElementCollector(updatedLIP.LinkedDocument);
                var elementsToCopy = collector.OfCategoryId(cp.CategoryId).WhereElementIsNotElementType().ToElements().ToList();

                var updatePbDelegate = new UpdateProgressBarDelegate(progressBar.SetValue);
                progressBar.Value   = 0;
                progressBar.Maximum = elementsToCopy.Count;

                var duplicated = 0;
                using (var tGroup = new TransactionGroup(recipientDoc))
                {
                    tGroup.Start("Duplicate Elements");
                    tGroup.IsFailureHandlingForcedModal = false;
                    var failureHanlder = new FailureHandler();

                    try
                    {
                        var options = new CopyPasteOptions();
                        options.SetDuplicateTypeNamesHandler(new HideAndAcceptDuplicateTypeNamesHandler());

                        double value = 0;
                        foreach (var sourceElement in elementsToCopy) //elements from link
                        {
                            value++;
                            System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(updatePbDelegate, System.Windows.Threading.DispatcherPriority.Background, new object[] { ProgressBar.ValueProperty, value });

                            var foundElements = from element in updatedLIP.LinkedElements.Values where element.SourceUniqueId == sourceElement.UniqueId && element.SourceLinkInstanceId == updatedLIP.InstanceId select element;
                            if (foundElements.Count() > 0)
                            {
                                var linkInfo      = foundElements.First();
                                var linkedElement = recipientDoc.GetElement(linkInfo.LinkedElementId);
                                if (null != linkedElement)
                                {
                                    if (linkInfo.LinkElementType == LinkType.ByMap || updateMode == UpdateMode.UpdateLocationOnly)
                                    {
                                        if (!linkInfo.Matched)
                                        {
                                            using (var trans = new Transaction(recipientDoc))
                                            {
                                                trans.Start("Move Element");
                                                var failureOption = trans.GetFailureHandlingOptions();
                                                failureOption.SetForcedModalHandling(false);
                                                failureOption.SetFailuresPreprocessor(failureHanlder);
                                                failureOption.SetClearAfterRollback(true);
                                                trans.SetFailureHandlingOptions(failureOption);

                                                try
                                                {
                                                    var moved = LinkedElementInfo.MoveLocation(sourceElement, linkedElement, updatedLIP.TransformValue);
                                                    linkInfo.Matched = moved;
                                                    if (updatedLIP.LinkedElements.ContainsKey(linkedElement.Id))
                                                    {
                                                        updatedLIP.LinkedElements.Remove(linkedElement.Id);
                                                        updatedLIP.LinkedElements.Add(linkedElement.Id, linkInfo);
                                                    }
                                                    trans.Commit();
                                                    duplicated++;
                                                }
                                                catch (Exception ex)
                                                {
                                                    trans.RollBack();
                                                    var message = ex.Message;
                                                }
                                            }
                                        }
                                        continue;
                                    }
                                    else if (updateMode == UpdateMode.ReplaceElements)
                                    {
                                        using (var trans = new Transaction(recipientDoc))
                                        {
                                            trans.Start("Delete Element");
                                            var failureOption = trans.GetFailureHandlingOptions();
                                            failureOption.SetForcedModalHandling(false);
                                            failureOption.SetFailuresPreprocessor(failureHanlder);
                                            failureOption.SetClearAfterRollback(true);
                                            trans.SetFailureHandlingOptions(failureOption);

                                            try
                                            {
                                                var deletedIds = recipientDoc.Delete(linkInfo.LinkedElementId);
                                                if (updatedLIP.LinkedElements.ContainsKey(linkInfo.LinkedElementId))
                                                {
                                                    updatedLIP.LinkedElements.Remove(linkInfo.LinkedElementId);
                                                }
                                                trans.Commit();
                                            }
                                            catch (Exception ex)
                                            {
                                                var message = ex.Message;
                                                trans.RollBack();
                                            }
                                        }
                                    }
                                }
                            }

                            var elementIds = new List <ElementId>();
                            elementIds.Add(sourceElement.Id);
                            try
                            {
                                Element copiedElement = null;
                                var     linkType      = LinkType.None;
                                using (var trans = new Transaction(recipientDoc))
                                {
                                    trans.Start("Copy Element");
                                    var failureOption = trans.GetFailureHandlingOptions();
                                    failureOption.SetForcedModalHandling(false);
                                    failureOption.SetFailuresPreprocessor(failureHanlder);
                                    failureOption.SetClearAfterRollback(true);
                                    trans.SetFailureHandlingOptions(failureOption);

                                    try
                                    {
                                        copiedElement = CopyByFamilyMaps(recipientDoc, updatedLIP, sourceElement, options);
                                        if (null != copiedElement)
                                        {
                                            linkType = LinkType.ByMap;
                                        }
                                        else
                                        {
                                            linkType = LinkType.ByCopy;
                                            var copiedElementIds = ElementTransformUtils.CopyElements(updatedLIP.LinkedDocument, elementIds, recipientDoc, updatedLIP.TransformValue, options);
                                            if (copiedElementIds.Count > 0)
                                            {
                                                var copiedElementId = copiedElementIds.First();
                                                copiedElement = recipientDoc.GetElement(copiedElementId);
                                            }
                                        }
                                        trans.Commit();
                                    }
                                    catch (Exception ex)
                                    {
                                        trans.RollBack();
                                        var message = ex.Message;
                                    }
                                }

                                if (null != copiedElement)
                                {
                                    using (var trans = new Transaction(recipientDoc))
                                    {
                                        trans.Start("Update Link Info");
                                        var failureOption = trans.GetFailureHandlingOptions();
                                        failureOption.SetForcedModalHandling(false);
                                        failureOption.SetFailuresPreprocessor(failureHanlder);
                                        failureOption.SetClearAfterRollback(true);
                                        trans.SetFailureHandlingOptions(failureOption);

                                        try
                                        {
                                            var linkInfo = new LinkedElementInfo(linkType, sourceElement, copiedElement, updatedLIP.InstanceId, updatedLIP.TransformValue);
                                            if (!linkInfo.Matched)
                                            {
                                                var moved = LinkedElementInfo.MoveLocation(sourceElement, copiedElement, updatedLIP.TransformValue);
                                                linkInfo.Matched = moved;
                                            }
                                            var updated = MoverDataStorageUtil.UpdateLinkedElementInfo(linkInfo, copiedElement);
                                            if (!updatedLIP.LinkedElements.ContainsKey(linkInfo.LinkedElementId))
                                            {
                                                updatedLIP.LinkedElements.Add(linkInfo.LinkedElementId, linkInfo);
                                            }
                                            duplicated++;
                                            trans.Commit();
                                        }
                                        catch (Exception ex)
                                        {
                                            trans.RollBack();
                                            var message = ex.Message;
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                var message = ex.Message;
                            }
                        }


                        if (updatedLIP.Categories.ContainsKey(cp.CategoryId))
                        {
                            cp.Selected = false;
                            updatedLIP.Categories.Remove(cp.CategoryId);
                            updatedLIP.Categories.Add(cp.CategoryId, cp);
                        }

                        tGroup.Assimilate();
                    }
                    catch (Exception ex)
                    {
                        tGroup.RollBack();
                        MessageBox.Show("Failed to duplicate elements in the category " + cp.CategoryName + "\n" + ex.Message, "Duplicate Elements", MessageBoxButton.OK, MessageBoxImage.Warning);
                    }
                }

                messageBuilder.AppendLine(duplicated.ToString() + " of " + elementsToCopy.Count.ToString() + " elements in " + cp.CategoryName + " has been successfully copied or updated.");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to duplicate elements.\n" + ex.Message, "Duplicate Elements", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            return(updatedLIP);
        }