/// <summary>
        /// Maps a category, cached per request
        /// </summary>
        /// <param name="model"></param>
        /// <param name="getSubAndParentCats"></param>
        /// <returns></returns>
        public static Category MapCategory(IPublishedContent model, bool getSubAndParentCats = false)
        {

            if (model != null)
            {
                var key = string.Format("umb-cat{0}-{1}", model.Id, getSubAndParentCats);
                if (!HttpContext.Current.Items.Contains(key))
                {

                    var pageModel = new Category(model);
                    pageModel.Description = model.GetPropertyValue<string>("description");
                    pageModel.Image = AppHelpers.GetMediaUrlFromProperty(model, "categoryImage");
                    pageModel.LockCategory = model.GetPropertyValue<bool>("lockCategory");
                    pageModel.ModerateAllTopicsInThisCategory = model.GetPropertyValue<bool>("moderateAllTopicsInThisCategory");
                    pageModel.ModerateAllPostsInThisCategory = model.GetPropertyValue<bool>("moderateAllPostsInThisCategory");
                    pageModel.SubCategories = new List<Category>();
                    pageModel.ParentCategories = new List<Category>();

                    // If this node has common properties then populate them
                    // I.e. SEO & Umbraco Properties
                    DialogueMapper.PopulateCommonUmbracoProperties(pageModel, model);

                    // Only get subcategories if the user has requested it
                    if (getSubAndParentCats)
                    {
                        var subCategories = model.Children.ToList();
                        if (model.Children.Any())
                        {
                            foreach (var publishedContent in subCategories)
                            {
                                pageModel.SubCategories.Add(MapCategory(publishedContent, true));
                            }
                        }

                        var path = model.Path;
                        if (!string.IsNullOrEmpty(path))
                        {
                            var catIds = path.Trim().Split(',').Select(x => Convert.ToInt32(x)).ToList();
                            catIds.Remove(model.Id);
                            var allNodes =
                                AppHelpers.UmbHelper()
                                    .TypedContent(catIds)
                                    .Where(x => x != null && x.DocumentTypeAlias == AppConstants.DocTypeForumCategory);
                            foreach (var cat in allNodes)
                            {
                                pageModel.ParentCategories.Add(MapCategory(cat));
                            }
                        }
                    }

                    HttpContext.Current.Items.Add(key, pageModel);
                }

                return HttpContext.Current.Items[key] as Category;
            }
            return null;
        }
        // var permissionSet = _permissionService.GetPermissions(category, role);
        //if (!permissionSet[AppConstants.PermissionDenyAccess].IsTicked)
        //{
        //    filteredCats.Add(category);
        //}


        /// <summary>
        /// Admin: so no need to check db, admin is all powerful
        /// </summary>
        private PermissionSet GetAdminPermissions(Category category, IMemberGroup memberGroup)
        {
            // Get all permissions
            var permissionList = GetAll();

            // Make a new entry in the results against each permission. All true (this is admin) except "Deny Access" 
            // and "Read Only" which should be false
            var permissionSet = new PermissionSet(permissionList.Select(permission => new CategoryPermission
            {
                Category = category,
                IsTicked = (permission.Name != AppConstants.PermissionDenyAccess && permission.Name != AppConstants.PermissionReadOnly),
                MemberGroup = memberGroup,
                Permission = permission
            }).ToList());


            return permissionSet;

        }
        /// <summary>
        /// Returns permission set based on category and role
        /// </summary>
        /// <param name="category"></param>
        /// <param name="memberGroup"></param>
        /// <returns></returns>
        public PermissionSet GetPermissions(Category category, IMemberGroup memberGroup)
        {
            if (memberGroup == null)
            {
                // This can only happen if the user has deleted a group, and not reassigned them
                // so in this occasion we just set them to a guest until the admin assigns them a new group
                memberGroup = ServiceFactory.MemberService.GetGroupByName(AppConstants.GuestRoleName);
            }

            // Pass the role in to see select which permissions to apply
            // Going to cache this per request, just to help with performance
            var objectContextKey = string.Concat(HttpContext.Current.GetHashCode().ToString("x"), "-", category.Id, "-", memberGroup.Id);
            if (!HttpContext.Current.Items.Contains(objectContextKey))
            {
                switch (memberGroup.Name)
                {
                    case AppConstants.AdminRoleName:
                        _permissions = GetAdminPermissions(category, memberGroup);
                        break;
                    case AppConstants.GuestRoleName:
                        _permissions = GetGuestPermissions(category, memberGroup);
                        break;
                    default:
                        _permissions = GetOtherPermissions(category, memberGroup);
                        break;
                }

                HttpContext.Current.Items.Add(objectContextKey, _permissions);
            }

            return HttpContext.Current.Items[objectContextKey] as PermissionSet;

        }
        /// <summary>
        /// Get permissions for roles other than those specially treated in this class
        /// </summary>
        /// <param name="category"></param>
        /// <param name="memberGroup"></param>
        /// <returns></returns>
        private PermissionSet GetOtherPermissions(Category category, IMemberGroup memberGroup)
        {
            // Get all permissions
            var permissionList = GetAll();

            // Get the known permissions for this role and category
            var categoryRow = ServiceFactory.CategoryPermissionService.GetCategoryRow(memberGroup.Id, category.Id);
            //var categoryRowPermissions = categoryRow.ToDictionary(catRow => catRow.Permission);

            // Load up the results with the permisions for this role / cartegory. A null entry for a permissions results in a new
            // record with a false value
            var permissions = new List<CategoryPermission>();
            foreach (var permission in permissionList)
            {
                permissions.Add(categoryRow.ContainsKey(permission)
                                    ? categoryRow[permission]
                                    : new CategoryPermission { Category = category, MemberGroup = memberGroup, IsTicked = false, Permission = permission });
            }

            var permissionSet = new PermissionSet(permissions);

            return permissionSet;

        }
        /// <summary>
        /// Guest = Not logged in, so only need to check the access permission
        /// </summary>
        /// <param name="category"></param>
        /// <param name="memberGroup"></param>
        private PermissionSet GetGuestPermissions(Category category, IMemberGroup memberGroup)
        {
            // Get all the permissions 
            var permissionList = GetAll();

            // Make a CategoryPermissionForRole for each permission that exists,
            // but only set the read-only permission to true for this role / category. All others false
            var permissions = permissionList.Select(permission => new CategoryPermission
            {
                Category = category,
                IsTicked = permission.Name == AppConstants.PermissionReadOnly,
                MemberGroup = memberGroup,
                Permission = permission
            }).ToList();

            
            // Deny Access may have been set (or left null) for guest for the category, so need to read for it
            var denyAccessPermission = ServiceFactory.CategoryPermissionService.GetByRole(memberGroup.Id)
                               .FirstOrDefault(x => x.CategoryId == category.Id &&
                                                    x.Permission.Name == AppConstants.PermissionDenyAccess &&
                                                    x.MemberGroupId == memberGroup.Id);

            // Set the Deny Access value in the results. If it's null for this role/category, record it as false in the results
            var categoryPermissionForRole = permissions.FirstOrDefault(x => x.Permission.Name == AppConstants.PermissionDenyAccess);
            if (categoryPermissionForRole != null)
            {
                categoryPermissionForRole.IsTicked = denyAccessPermission != null && denyAccessPermission.IsTicked;
            }

            var permissionSet = new PermissionSet(permissions);


            return permissionSet;

        }
 /// <summary>
 /// Return notifications for a specified user and category
 /// </summary>
 /// <param name="user"></param>
 /// <param name="category"></param>
 /// <returns></returns>
 public IList<CategoryNotification> GetByUserAndCategory(Member user, Category category)
 {
     return ContextPerRequest.Db.CategoryNotification.Where(x => x.CategoryId == category.Id && x.MemberId == user.Id).ToList();
 }
 /// <summary>
 /// Return all notifications by a specified category
 /// </summary>
 /// <param name="category"></param>
 /// <returns></returns>
 public IList<CategoryNotification> GetByCategory(Category category)
 {
     return ContextPerRequest.Db.CategoryNotification.AsNoTracking().Where(x => x.CategoryId == category.Id).ToList();
 }
        private void NotifyNewTopics(Category cat)
        {
            // *CHANGE THIS TO BE CALLED LIKE THE BADGES VIA AN AJAX Method* 
            // TODO: This really needs to be an async call so it doesn't hang when a user creates  
            //  a topic if there are 1000's of users

            // Get all notifications for this category
            var notifications = ServiceFactory.CategoryNotificationService.GetByCategory(cat).Select(x => x.MemberId).ToList();

            if (notifications.Any())
            {
                // remove the current user from the notification, don't want to notify yourself that you 
                // have just made a topic!
                notifications.Remove(CurrentMember.Id);

                if (notifications.Count > 0)
                {
                    // Now get all the users that need notifying
                    var usersToNotify = ServiceFactory.MemberService.GetUsersById(notifications);

                    // Create the email
                    var sb = new StringBuilder();
                    sb.AppendFormat("<p>{0}</p>", string.Format(Lang("Topic.Notification.NewTopics"), cat.Name));
                    sb.AppendFormat("<p>{0}</p>", string.Concat(Settings.ForumRootUrlWithDomain, cat.Url));

                    // create the emails and only send them to people who have not had notifications disabled
                    var emails = usersToNotify.Where(x => x.DisableEmailNotifications != true).Select(user => new Email
                    {
                        Body = ServiceFactory.EmailService.EmailTemplate(user.UserName, sb.ToString()),
                        EmailFrom = Settings.NotificationReplyEmailAddress,
                        EmailTo = user.Email,
                        NameTo = user.UserName,
                        Subject = string.Concat(Lang("Topic.Notification.Subject"), Settings.ForumName)
                    }).ToList();

                    // and now pass the emails in to be sent
                    ServiceFactory.EmailService.SendMail(emails);
                }
            }
        }