public CategoryTree Save(SaveCategoryTreeRequest request)
        {
            IList <Category> createdCategories = new List <Category>();

            IList <Category> updatedCategories = new List <Category>();

            IList <Category> deletedCategories = new List <Category>();

            var createNew = request.Id.HasDefaultValue();

            var selectedCategorizableItemsFuture = Repository.AsQueryable <CategoryTreeCategorizableItem>()
                                                   .Where(i => i.CategoryTree.Id == request.Id)
                                                   .ToFuture();

            IEnumerable <Category> existingCategories;
            CategoryTree           categoryTree;

            if (createNew)
            {
                existingCategories = new List <Category>();
                categoryTree       = new CategoryTree();
            }
            else
            {
                existingCategories = Repository.AsQueryable <Category>().Where(node => node.CategoryTree.Id == request.Id).ToFuture();
                categoryTree       = Repository.AsQueryable <CategoryTree>().Where(s => s.Id == request.Id).ToFuture().First();
            }

            List <CategoryTreeCategorizableItem> itemsToRemove = null;
            List <Guid> itemsToAdd = null;

            if (request.UseForCategorizableItems != null)
            {
                var selectedItems = selectedCategorizableItemsFuture.ToList();
                itemsToRemove = selectedItems.Where(s => !request.UseForCategorizableItems.Exists(c => c == s.CategorizableItem.Id)).ToList();
                if (!createNew)
                {
                    foreach (var categoryTreeCategorizableItem in itemsToRemove)
                    {
                        var categorizableItemName = categoryTreeCategorizableItem.CategorizableItem.Name;
                        var accessor = CategoryAccessors.Accessors.First(ca => ca.Name == categorizableItemName);
                        if (accessor.CheckIsUsed(Repository, categoryTree).Value > 0)
                        {
                            throw new CmsException("Cannot deselect categorizable items that have usages");
                        }
                    }
                }
                itemsToAdd = request.UseForCategorizableItems.Where(id => !selectedItems.Exists(s => s.CategorizableItem.Id == id)).ToList();
            }

            UnitOfWork.BeginTransaction();

            categoryTree.Title   = request.Title;
            categoryTree.Version = request.Version;
            categoryTree.Macro   = request.Macro;

            Repository.Save(categoryTree);

            if (itemsToRemove != null)
            {
                itemsToRemove.ForEach(Repository.Delete);
                itemsToAdd.ForEach(
                    id =>
                    Repository.Save(new CategoryTreeCategorizableItem {
                    CategoryTree = categoryTree, CategorizableItem = Repository.AsProxy <CategorizableItem>(id)
                }));
            }

            var existingCategoryList = existingCategories.ToList();

            SaveCategoryTreeNodes(categoryTree, request.RootNodes, null, existingCategoryList, createdCategories, updatedCategories);

            foreach (var category in existingCategoryList)
            {
                CategoryNodeService.DeleteRelations(category);
                Repository.Delete(category);
                deletedCategories.Add(category);
            }

            UnitOfWork.Commit();

            foreach (var category in createdCategories)
            {
                RootEvents.Instance.OnCategoryCreated(category);
            }

            foreach (var category in updatedCategories)
            {
                RootEvents.Instance.OnCategoryUpdated(category);
            }

            foreach (var category in deletedCategories)
            {
                RootEvents.Instance.OnCategoryDeleted(category);
            }

            if (createNew)
            {
                RootEvents.Instance.OnCategoryTreeCreated(categoryTree);
            }
            else
            {
                RootEvents.Instance.OnCategoryTreeUpdated(categoryTree);
            }

            return(categoryTree);
        }
        public CategoryTree Save(SaveCategoryTreeRequest request)
        {
            IList<Category> createdCategories = new List<Category>();

            IList<Category> updatedCategories = new List<Category>();

            IList<Category> deletedCategories = new List<Category>();

            var createNew = request.Id.HasDefaultValue();

            var selectedCategorizableItemsFuture = Repository.AsQueryable<CategoryTreeCategorizableItem>()
                .Where(i => i.CategoryTree.Id == request.Id)
                .ToFuture();

            IEnumerable<Category> existingCategories;
            CategoryTree categoryTree;
            if (createNew)
            {
                existingCategories = new List<Category>();
                categoryTree = new CategoryTree();
            }
            else
            {
                existingCategories = Repository.AsQueryable<Category>().Where(node => node.CategoryTree.Id == request.Id).ToFuture();
                categoryTree = Repository.AsQueryable<CategoryTree>().Where(s => s.Id == request.Id).ToFuture().First();
            }

            List<CategoryTreeCategorizableItem> itemsToRemove = null;
            List<Guid> itemsToAdd = null;
            if (request.UseForCategorizableItems != null)
            {
                var selectedItems = selectedCategorizableItemsFuture.ToList();
                itemsToRemove = selectedItems.Where(s => !request.UseForCategorizableItems.Exists(c => c == s.CategorizableItem.Id)).ToList();
                if (!createNew)
                {
                    foreach (var categoryTreeCategorizableItem in itemsToRemove)
                    {
                        var categorizableItemName = categoryTreeCategorizableItem.CategorizableItem.Name;
                        var accessor = CategoryAccessors.Accessors.First(ca => ca.Name == categorizableItemName);
                        if (accessor.CheckIsUsed(Repository, categoryTree).Value > 0)
                        {
                            throw new CmsException("Cannot deselect categorizable items that have usages");
                        }
                    }
                }
                itemsToAdd = request.UseForCategorizableItems.Where(id => !selectedItems.Exists(s => s.CategorizableItem.Id == id)).ToList();
            }

            UnitOfWork.BeginTransaction();

            categoryTree.Title = request.Title;
            categoryTree.Version = request.Version;
            categoryTree.Macro = request.Macro;

            Repository.Save(categoryTree);

            if (itemsToRemove != null)
            {
                itemsToRemove.ForEach(Repository.Delete);
                itemsToAdd.ForEach(
                    id =>
                    Repository.Save(new CategoryTreeCategorizableItem { CategoryTree = categoryTree, CategorizableItem = Repository.AsProxy<CategorizableItem>(id) }));
            }

            var existingCategoryList = existingCategories.ToList();
            SaveCategoryTreeNodes(categoryTree, request.RootNodes, null, existingCategoryList, createdCategories, updatedCategories);

            foreach (var category in existingCategoryList)
            {
                CategoryNodeService.DeleteRelations(category);
                Repository.Delete(category);
                deletedCategories.Add(category);
            }

            UnitOfWork.Commit();

            foreach (var category in createdCategories)
            {
                RootEvents.Instance.OnCategoryCreated(category);
            }

            foreach (var category in updatedCategories)
            {
                RootEvents.Instance.OnCategoryUpdated(category);
            }

            foreach (var category in deletedCategories)
            {
                RootEvents.Instance.OnCategoryDeleted(category);
            }

            if (createNew)
            {
                RootEvents.Instance.OnCategoryTreeCreated(categoryTree);
            }
            else
            {
                RootEvents.Instance.OnCategoryTreeUpdated(categoryTree);
            }

            return categoryTree;
        }
        /// <summary>
        /// Puts the category specified in request.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns>
        ///   <c>PutCategoriesResponse</c> with updated category data.
        /// </returns>
        public PutCategoryTreeResponse Put(PutCategoryTreeRequest request)
        {
            var serviceRequest = new SaveCategoryTreeRequest
            {
                Id = request.Id ?? Guid.Empty, 
                Title = request.Data.Name, 
                Version = request.Data.Version,
                UseForCategorizableItems = request.Data.UseForCategorizableItems
            };
            IList<Module.Root.Services.Categories.CategoryNodeModel> rootNodes = new List<Module.Root.Services.Categories.CategoryNodeModel>();
            if (request.Data.Nodes != null)
            {
                foreach (var node in request.Data.Nodes)
                {
                    rootNodes.Add(RemapChildren(node, null));
                }
                serviceRequest.RootNodes = rootNodes;
            }

            var categoryTree = categoryTreeService.Save(serviceRequest);

            return new PutCategoryTreeResponse { Data = categoryTree.Id };
        }