/// <summary>
        /// Used for the DeleteContentOfType(s) methods to find content items to be trashed based on the content type ids passed in
        /// </summary>
        /// <typeparam name="TContent"></typeparam>
        /// <param name="contentService"></param>
        /// <param name="contentTypeIds">The content type ids being deleted</param>
        /// <param name="rootItems"></param>
        /// <param name="repository"></param>
        /// <returns>
        /// The content items to be trashed
        /// </returns>
        /// <remarks>
        /// An internal extension method used for the DeleteContentOfTypes (DeleteMediaOfTypes) methods so that logic can be shared to avoid code duplication.
        /// </remarks>
        internal static IEnumerable <TContent> TrackTrashedForDeleteContentOfTypes <TContent>(this IContentServiceBase contentService,
                                                                                              IEnumerable <int> contentTypeIds,
                                                                                              IDictionary <string, TContent> rootItems,
                                                                                              IRepositoryVersionable <int, TContent> repository)
            where TContent : IContentBase
        {
            const int pageSize         = 10000;
            var       contentToRecycle = new List <TContent>();

            //iterate over the root items found in the collection to be deleted, then discover which descendant items
            //need to be moved to the recycle bin
            foreach (var content in rootItems)
            {
                //Look for children of current content and move that to trash before the current content is deleted
                var c               = content;
                var pathMatch       = string.Format("{0},", c.Value.Path);
                var descendantQuery = Query <TContent> .Builder.Where(x => x.Path.StartsWith(pathMatch));

                long pageIndex = 0;
                int  currentPageSize;

                do
                {
                    long total;

                    var descendants = repository.GetPagedResultsByQuery(descendantQuery, pageIndex, pageSize, out total, "umbracoNode.id", Direction.Ascending, true).ToArray();

                    foreach (var d in descendants)
                    {
                        //track for recycling if this item is not of a contenttype that is being deleted
                        if (contentTypeIds.Contains(d.ContentTypeId) == false)
                        {
                            contentToRecycle.Add(d);
                        }
                    }

                    // need to store decendants count before filtering, in order for loop to work correctly
                    currentPageSize = descendants.Length;

                    pageIndex++;
                } while (currentPageSize == pageSize);
            }

            return(contentToRecycle);
        }
        /// <summary>
        /// Used for the DeleteContentOfType(s) methods to find content items to be deleted based on the content type ids passed in
        /// </summary>
        /// <typeparam name="TContent"></typeparam>
        /// <param name="contentService"></param>
        /// <param name="contentTypeIds">The content type ids being deleted</param>
        /// <param name="repository"></param>
        /// <param name="rootItems">
        /// Returns a dictionary (path, TContent) of the root items discovered in the data set of items to be deleted, this can then be used
        /// to search for content that needs to be trashed as a result of this.
        /// </param>
        /// <returns>
        /// The content items to be deleted
        /// </returns>
        /// <remarks>
        /// An internal extension method used for the DeleteContentOfTypes (DeleteMediaOfTypes) methods so that logic can be shared to avoid code duplication.
        /// </remarks>
        internal static IEnumerable <TContent> TrackDeletionsForDeleteContentOfTypes <TContent>(this IContentServiceBase contentService,
                                                                                                IEnumerable <int> contentTypeIds,
                                                                                                IRepositoryVersionable <int, TContent> repository,
                                                                                                out IDictionary <string, TContent> rootItems)
            where TContent : IContentBase
        {
            var contentToDelete = new List <TContent>();

            //track the 'root' items of the collection of nodes discovered to delete, we need to use
            //these items to lookup descendants that are not of this doc type so they can be transfered
            //to the recycle bin
            rootItems = new Dictionary <string, TContent>();

            var query = Query <TContent> .Builder.Where(x => contentTypeIds.Contains(x.ContentTypeId));

            //TODO: What about content that has the contenttype as part of its composition?

            long      pageIndex = 0;
            const int pageSize  = 10000;
            int       currentPageSize;

            do
            {
                long total;

                //start at the highest level
                var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "umbracoNode.level", Direction.Ascending, true).ToArray();

                // need to store decendants count before filtering, in order for loop to work correctly
                currentPageSize = contents.Length;

                //loop through the items, check if if the item exists already in the hierarchy of items tracked
                //and if not, we need to add it as a 'root' item to be used to lookup later
                foreach (var content in contents)
                {
                    var pathParts = content.Path.Split(',');
                    var found     = false;

                    for (int i = 1; i < pathParts.Length; i++)
                    {
                        var currPath = "-1," + string.Join(",", Enumerable.Range(1, i).Select(x => pathParts[x]));
                        if (rootItems.Keys.Contains(currPath))
                        {
                            //this content item's ancestor already exists in the root collection
                            found = true;
                            break;
                        }
                    }

                    if (found == false)
                    {
                        rootItems[content.Path] = content;
                    }

                    //track content for deletion
                    contentToDelete.Add(content);
                }

                pageIndex++;
            } while (currentPageSize == pageSize);

            return(contentToDelete);
        }