Inheritance: DotNetNuke.Modules.ActiveForums.ForumController
        public XmlRpcStruct MarkTopicsRead(IEnumerable<int> topicIds)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();

            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");
            var topicIdsStr = topicIds.Aggregate(string.Empty, (current, topicId) => current + (topicId.ToString() + ";"));

            fc.MarkTopicsRead(portalId, forumModuleId, userId, forumIds, topicIdsStr);

            return new XmlRpcStruct
            {
                {"result", true}
            };
        }
        private XmlRpcStruct GetLatestTopics(int startIndex, int endIndex, string searchId, object filters)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var maxRows = endIndex + 1 - startIndex;

            var latestTopics = fc.GetLatestTopics(portalId, forumModuleId, userId, forumIds, startIndex, maxRows).ToList();

            return new XmlRpcStruct
                       {
                           {"result", true},
                           {"total_topic_num", latestTopics.Count > 0 ? latestTopics[0].TopicCount : 0},
                           {"topics", latestTopics.Select(t => new ExtendedTopicStructure{ 
                                                   TopicId = t.TopicId.ToString(),
                                                   AuthorAvatarUrl = GetAvatarUrl(t.LastReplyAuthorId),
                                                   AuthorId = t.LastReplyAuthorId.ToString(),
                                                   AuthorName = GetLastReplyAuthorName(mainSettings, t).ToBytes(),
                                                   ForumId = t.ForumId.ToString(),
                                                   ForumName = t.ForumName.ToBytes(),
                                                   HasNewPosts =  (t.LastReplyId < 0 && t.TopicId > t.UserLastTopicRead) || t.LastReplyId > t.UserLastReplyRead,
                                                   IsLocked = t.IsLocked,
                                                   IsSubscribed = t.SubscriptionType > 0,
                                                   CanSubscribe = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fc.GetForumPermissions(t.ForumId).CanSubscribe), // GetforumPermissions uses cache so it shouldn't be a performance issue
                                                   ReplyCount = t.ReplyCount,
                                                   Summary = GetSummary(null, t.LastReplyBody).ToBytes(),
                                                   ViewCount = t.ViewCount,
                                                   DateCreated = t.LastReplyDate,
                                                   Title = HttpUtility.HtmlDecode(t.Subject + string.Empty).ToBytes()
                                               }).ToArray()}
                       };
        }
        private XmlRpcStruct GetTopicStatus(IEnumerable<int> topicIds)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");

            var topicIdsString = topicIds.Aggregate(string.Empty, (current, topicId) => current + (topicId.ToString() + ";"));

            var unreadTopics = fc.GetTopicStatus(portalId, forumModuleId, userId, forumIds, topicIdsString).ToList();

            return new XmlRpcStruct
                       {
                           {"result", true},
                           {"status", unreadTopics.Select(t => new TopicStatusStructure(){ 
                                                   TopicId = t.TopicId.ToString(),
                                                   HasNewPosts =  (t.LastReplyId < 0 && t.TopicId > t.UserLastTopicRead) || t.LastReplyId > t.UserLastReplyRead,
                                                   IsLocked = t.IsLocked,
                                                   IsSubscribed = t.SubscriptionType > 0,
                                                   CanSubscribe = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fc.GetForumPermissions(t.ForumId).CanSubscribe), // GetforumPermissions uses cache so it shouldn't be a performance issue
                                                   ReplyCount = t.ReplyCount,
                                                   ViewCount = t.ViewCount,
                                                   LastReplyDate = t.LastReplyDate
                                               }).ToArray()}
                       };
        }
        private TopicListStructure GetTopic(int forumId, int startIndex, int endIndex, string mode = null)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;

            var fc = new AFTForumController();

            var fp = fc.GetForumPermissions(forumId);

            if (!ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanRead))
                throw new XmlRpcFaultException(100, "No Read Permissions");

            var maxRows = endIndex + 1 - startIndex;

            var forumTopicsSummary = fc.GetForumTopicSummary(portalId, forumModuleId, forumId, aftContext.UserId, mode);
            var forumTopics = fc.GetForumTopics(portalId, forumModuleId, forumId, aftContext.UserId, startIndex, maxRows, mode);

            var canSubscribe = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanSubscribe);

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var profilePath = string.Format("{0}://{1}{2}", Context.Request.Url.Scheme, Context.Request.Url.Host, VirtualPathUtility.ToAbsolute("~/profilepic.ashx"));

            var forumTopicsStructure = new TopicListStructure
                                           {
                                               CanPost = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanCreate),
                                               ForumId = forumId.ToString(),
                                               ForumName = forumTopicsSummary.ForumName.ToBytes(),
                                               TopicCount = forumTopicsSummary.TopicCount,
                                               Topics = forumTopics.Select(t => new TopicStructure{ 
                                                   TopicId = t.TopicId.ToString(),
                                                   AuthorAvatarUrl = string.Format("{0}?userId={1}&w=64&h=64", profilePath, t.AuthorId),
                                                   AuthorName = GetAuthorName(mainSettings, t).ToBytes(),
                                                   CanSubscribe = canSubscribe,
                                                   ForumId = forumId.ToString(),
                                                   HasNewPosts = (t.LastReplyId < 0 && t.TopicId > t.UserLastTopicRead) || t.LastReplyId > t.UserLastReplyRead,
                                                   IsLocked = t.IsLocked,
                                                   IsSubscribed = t.SubscriptionType > 0,
                                                   LastReplyDate = t.LastReplyDate,
                                                   ReplyCount = t.ReplyCount,
                                                   Summary = GetSummary(t.Summary, t.Body).ToBytes(),
                                                   ViewCount = t.ViewCount,
                                                   Title = HttpUtility.HtmlDecode(t.Subject + string.Empty).ToBytes()
                                               }).ToArray()
                                           };



            return forumTopicsStructure;
        }
        private XmlRpcStruct NewTopic(int forumId, string subject, string body, string prefixId, IEnumerable<string> attachmentIds, string groupId)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;

            var fc = new AFTForumController();

            var forumInfo = fc.GetForum(portalId, forumModuleId, forumId);

            // Verify Post Permissions
            if (!ActiveForums.Permissions.HasPerm(forumInfo.Security.Create, aftContext.ForumUser.UserRoles))
            {
                return new XmlRpcStruct
                                {
                                    {"result", "false"}, //"true" for success
                                    {"result_text", "Not Authorized to Post".ToBytes()}, 
                                };
            }

            // Build User Permissions
            var canModApprove = ActiveForums.Permissions.HasPerm(forumInfo.Security.ModApprove, aftContext.ForumUser.UserRoles);
            var canTrust = ActiveForums.Permissions.HasPerm(forumInfo.Security.Trust, aftContext.ForumUser.UserRoles);
            var userProfile = aftContext.UserId > 0 ? aftContext.ForumUser.Profile : new UserProfileInfo { TrustLevel = -1 };
            var userIsTrusted = Utilities.IsTrusted((int)forumInfo.DefaultTrustValue, userProfile.TrustLevel, canTrust, forumInfo.AutoTrustLevel, userProfile.PostCount);

            // Determine if the post should be approved
            var isApproved = !forumInfo.IsModerated || userIsTrusted || canModApprove;

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var dnnUser = Entities.Users.UserController.GetUserById(portalId, aftContext.UserId);

            var authorName = GetAuthorName(mainSettings, dnnUser);

            var themePath = string.Format("{0}://{1}{2}", Context.Request.Url.Scheme, Context.Request.Url.Host, VirtualPathUtility.ToAbsolute("~/DesktopModules/activeforums/themes/" + mainSettings.Theme + "/"));

            subject = Utilities.CleanString(portalId, subject, false, EditorTypes.TEXTBOX, forumInfo.UseFilter, false, forumModuleId, themePath, false);
            body = Utilities.CleanString(portalId, TapatalkToHtml(body), forumInfo.AllowHTML, EditorTypes.HTMLEDITORPROVIDER, forumInfo.UseFilter, false, forumModuleId, themePath, forumInfo.AllowEmoticons);

            // Create the topic

            var ti = new TopicInfo();
            var dt = DateTime.Now;
            ti.Content.DateCreated = dt;
            ti.Content.DateUpdated = dt;
            ti.Content.AuthorId = aftContext.UserId;
            ti.Content.AuthorName = authorName;
            ti.Content.IPAddress = Context.Request.UserHostAddress;
            ti.TopicUrl = string.Empty;
            ti.Content.Body = body;
            ti.Content.Subject = subject;
            ti.Content.Summary = string.Empty;

            ti.IsAnnounce = false;
            ti.IsPinned = false;
            ti.IsLocked = false;
            ti.IsDeleted = false;
            ti.IsArchived = false;

            ti.StatusId = -1;
            ti.TopicIcon = string.Empty;
            ti.TopicType = 0;

            ti.IsApproved = isApproved;

            // Save the topic
            var tc = new TopicsController();
            var topicId = tc.TopicSave(portalId, ti);
            ti = tc.Topics_Get(portalId, forumModuleId, topicId, forumId, -1, false);

            if (ti == null)
            {
                return new XmlRpcStruct
                                {
                                    {"result", "false"}, //"true" for success
                                    {"result_text", "Error Creating Post".ToBytes()}, 
                                };
            }

            // Update stats
            tc.Topics_SaveToForum(forumId, topicId, portalId, forumModuleId);
            if (ti.IsApproved && ti.Author.AuthorId > 0)
            {
                var uc = new ActiveForums.Data.Profiles();
                uc.Profile_UpdateTopicCount(portalId, ti.Author.AuthorId);
            }


            try
            {
                // Clear the cache
                var cachekey = string.Format("AF-FV-{0}-{1}", portalId, forumModuleId);
                DataCache.CacheClearPrefix(cachekey);

                // Subscribe the user if they have auto-subscribe set.
                if (userProfile.PrefSubscriptionType != SubscriptionTypes.Disabled && !(Subscriptions.IsSubscribed(portalId, forumModuleId, forumId, topicId, SubscriptionTypes.Instant, aftContext.UserId)))
                {
                    new SubscriptionController().Subscription_Update(portalId, forumModuleId, forumId, topicId, (int)userProfile.PrefSubscriptionType, aftContext.UserId, aftContext.ForumUser.UserRoles);
                }

                if (isApproved)
                {
                    // Send User Notifications
                    Subscriptions.SendSubscriptions(portalId, forumModuleId, aftContext.ModuleSettings.ForumTabId, forumInfo, topicId, 0, ti.Content.AuthorId);

                    // Add Journal entry
                    var forumTabId = aftContext.ModuleSettings.ForumTabId;
                    var fullURL = new ControlUtils().BuildUrl(forumTabId, forumModuleId, forumInfo.ForumGroup.PrefixURL, forumInfo.PrefixURL, forumInfo.ForumGroupId, forumInfo.ForumID, topicId, ti.TopicUrl, -1, -1, string.Empty, 1, -1, forumInfo.SocialGroupId);
                    new Social().AddTopicToJournal(portalId, forumModuleId, forumId, topicId, ti.Author.AuthorId, fullURL, ti.Content.Subject, string.Empty, ti.Content.Body, forumInfo.ActiveSocialSecurityOption, forumInfo.Security.Read, forumInfo.SocialGroupId);
                }
                else
                {
                    // Send Mod Notifications
                    var mods = Utilities.GetListOfModerators(portalId, forumId);
                    var notificationType = NotificationsController.Instance.GetNotificationType("AF-ForumModeration");
                    var notifySubject = Utilities.GetSharedResource("NotificationSubjectTopic");
                    notifySubject = notifySubject.Replace("[DisplayName]", dnnUser.DisplayName);
                    notifySubject = notifySubject.Replace("[TopicSubject]", ti.Content.Subject);
                    var notifyBody = Utilities.GetSharedResource("NotificationBodyTopic");
                    notifyBody = notifyBody.Replace("[Post]", ti.Content.Body);
                    var notificationKey = string.Format("{0}:{1}:{2}:{3}:{4}", aftContext.ModuleSettings.ForumTabId, forumModuleId, forumId, topicId, 0);

                    var notification = new Notification
                    {
                        NotificationTypeID = notificationType.NotificationTypeId,
                        Subject = notifySubject,
                        Body = notifyBody,
                        IncludeDismissAction = false,
                        SenderUserID = dnnUser.UserID,
                        Context = notificationKey
                    };

                    NotificationsController.Instance.SendNotification(notification, portalId, null, mods);
                }

            }
            catch (Exception ex)
            {
                Services.Exceptions.Exceptions.LogException(ex);
            }


            var result = new XmlRpcStruct
            {
                {"result", true}, //"true" for success
               // {"result_text", "OK".ToBytes()}, 
                {"topic_id", ti.TopicId.ToString()},
            };

            if (!isApproved)
                result.Add("state", 1);

            return result;

        }
        public XmlRpcStruct GetParticipatedForums()
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");

            var subscribedForums = fc.GetParticipatedForums(portalId, forumModuleId, userId, forumIds).ToList();

            return new XmlRpcStruct
                       {
                           {"total_forums_num", subscribedForums.Count},
                           {"forums", subscribedForums.Select(f => new ListForumStructure
                                {
                                    ForumId = f.ForumId.ToString(),
                                    ForumName = f.ForumName.ToBytes(),
                                    IsProtected = false,
                                    HasNewPosts =  f.LastPostDate > f.LastAccessDate
                                }).ToArray()}
                       };
        }
        public XmlRpcStruct GetForumStatus(params object[] parameters)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead") + string.Empty;

            // Clean up our forum id list before we split it up.
            forumIds = Regex.Replace(forumIds, @"\;+$", string.Empty);

            var forumIdList = !string.IsNullOrWhiteSpace(forumIds)
                                  ? forumIds.Split(';').Select(int.Parse).ToList()
                                  : new List<int>();

            // Intersect requested forums with avialable forums
            var requestedForumIds = (parameters != null && parameters.Any())
                                        ? ((object[])parameters[0]).Select(Convert.ToInt32).Where(forumIdList.Contains)
                                        : new int[] { };

            // Convert the new list of forums back to a string for the proc.
            forumIds = requestedForumIds.Aggregate(string.Empty, (current, id) => current + (id.ToString() + ";"));

            var forumStatus = fc.GetForumStatus(portalId, forumModuleId, userId, forumIds).ToList();

            return new XmlRpcStruct
                       {
                           {"forums", forumStatus.Select(f => new ListForumStructure
                                {
                                    ForumId = f.ForumId.ToString(),
                                    ForumName = f.ForumName.ToBytes(),
                                    IsProtected = false,
                                    HasNewPosts =  f.LastPostDate > f.LastAccessDate
                                }).ToArray()}
                       };
        }
        private XmlRpcStruct SearchPosts(string searchString, int startIndex, int endIndex, string searchId)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Verify Search Permissions
            var searchPermissions = aftContext.ModuleSettings.SearchPermission;
            if (searchPermissions == ActiveForumsTapatalkModuleSettings.SearchPermissions.Disabled || (userId <= 0 && searchPermissions == ActiveForumsTapatalkModuleSettings.SearchPermissions.RegisteredUsers))
                throw new XmlRpcFaultException(102, "Insufficent Search Permissions");

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var maxRows = endIndex + 1 - startIndex;

            var searchResults = fc.SearchPosts(portalId, forumModuleId, userId, forumIds, searchString, startIndex, maxRows, searchId, mainSettings);

            if (searchResults == null)
                throw new XmlRpcFaultException(101, "Search Error");

            return new XmlRpcStruct
            {
                {"total_post_num", searchResults.TotalPosts },
                {"search_id", searchResults.SearchId.ToString() },
                {"posts", searchResults.Topics.Select(t => new ExtendedPostStructure { 
                                        TopicId = t.TopicId.ToString(),
                                        AuthorAvatarUrl = GetAvatarUrl(t.AuthorId),
                                        AuthorId = t.AuthorId.ToString(),
                                        AuthorName = GetAuthorName(mainSettings, t).ToBytes(),
                                        ForumId = t.ForumId.ToString(),
                                        ForumName = t.ForumName.ToBytes(),
                                        PostID = t.ContentId.ToString(),
                                        Summary = GetSummary(null, t.Body).ToBytes(),
                                        PostDate = t.DateCreated,
                                        TopicTitle = HttpUtility.HtmlDecode(t.Subject + string.Empty).ToBytes(),
                                        PostTitle = HttpUtility.HtmlDecode(t.PostSubject + string.Empty).ToBytes()
                                    }).ToArray()}
            };
        }
        private ForumStructure[] GetForums(string forumId, bool includeDescription)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, "CanRead");
            var forumTable = fc.GetForumView(aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, aftContext.UserId, aftContext.ForumUser.IsSuperUser, forumIds);
            var forumSubscriptions = fc.GetSubscriptionsForUser(aftContext.ModuleSettings.ForumModuleId, aftContext.UserId, null, 0).ToList();

            var result = new List<ForumStructure>();

            // Note that all the fields in the DataTable are strings if they come back from the cache, so they have to be converted appropriately.

            // Get the distict list of groups
            /*
            var groups = forumTable.AsEnumerable()
                .Select(r => new
                {
                    ID = Convert.ToInt32(r["ForumGroupId"]),
                    Name = r["GroupName"].ToString(),
                    SortOrder = Convert.ToInt32(r["GroupSort"]),
                    Active = Convert.ToBoolean(r["GroupActive"])
                }).Distinct().Where(o => o.Active).OrderBy(o => o.SortOrder);
             */

            // Get all forums the user can read
            var visibleForums = forumTable.AsEnumerable()
                .Select(f => new
                {
                    ID = Convert.ToInt32(f["ForumId"]),
                    ForumGroupId = Convert.ToInt32(f["ForumGroupId"]),
                    Name = f["ForumName"].ToString(),
                    Description = f["ForumDesc"].ToString(),
                    ParentForumId = Convert.ToInt32(f["ParentForumId"]),
                    ReadRoles = f["CanRead"].ToString(),
                    SubscribeRoles = f["CanSubscribe"].ToString(),
                    LastRead = Convert.ToDateTime(f["LastRead"]),
                    LastPostDate = Convert.ToDateTime(f["LastPostDate"]),
                    SortOrder = Convert.ToInt32(f["ForumSort"]),
                    Active = Convert.ToBoolean(f["ForumActive"])
                })
                .Where(o => o.Active && ActiveForums.Permissions.HasPerm(o.ReadRoles, aftContext.ForumUser.UserRoles))
                .OrderBy(o => o.SortOrder).ToList();


            if (forumId.StartsWith("G"))
            {
                var groupId = Convert.ToInt32(forumId.Substring(1));

                foreach (var forum in visibleForums.Where(f => f.ForumGroupId == groupId && f.ParentForumId == 0))
                {
                    var forumStructure = new ForumStructure
                    {
                        ForumId = forum.ID.ToString(),
                        Name = Utilities.StripHTMLTag(forum.Name).ToBytes(),
                        Description = includeDescription ? Utilities.StripHTMLTag(forum.Description).ToBytes() : string.Empty.ToBytes(),
                        ParentId = forumId,
                        LogoUrl = null,
                        HasNewPosts = aftContext.UserId > 0 && forum.LastPostDate > forum.LastRead,
                        IsProtected = false,
                        IsSubscribed = forumSubscriptions.Any(fs => fs.ForumId == forum.ID),
                        CanSubscribe = ActiveForums.Permissions.HasPerm(forum.SubscribeRoles, aftContext.ForumUser.UserRoles),
                        Url = null,
                        IsGroup = false
                    };

                    result.Add(forumStructure);
                }
            }
            else
            {
                foreach (var forum in visibleForums.Where(f => f.ParentForumId == int.Parse(forumId)))
                {
                    var forumStructure = new ForumStructure
                    {
                        ForumId = forum.ID.ToString(),
                        Name = Utilities.StripHTMLTag(forum.Name).ToBytes(),
                        Description = includeDescription ? Utilities.StripHTMLTag(forum.Description).ToBytes() : string.Empty.ToBytes(),
                        ParentId = forumId,
                        LogoUrl = null,
                        HasNewPosts = aftContext.UserId > 0 && forum.LastPostDate > forum.LastRead,
                        IsProtected = false,
                        IsSubscribed = forumSubscriptions.Any(fs => fs.ForumId == forum.ID),
                        CanSubscribe = ActiveForums.Permissions.HasPerm(forum.SubscribeRoles, aftContext.ForumUser.UserRoles),
                        Url = null,
                        IsGroup = false
                    };

                    result.Add(forumStructure);
                }
            }

            return result.ToArray();
        }
        private XmlRpcStruct Subscribe(int? forumId, int? topicId, bool unsubscribe)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            if (!forumId.HasValue && !topicId.HasValue)
                return new XmlRpcStruct { { "result", "0" }, { "result_text", "Bad Request".ToBytes() } };


            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;

            // Look up the forum Id if needed
            if (!forumId.HasValue)
            {
                var ti = new TopicsController().Topics_Get(portalId, forumModuleId, topicId.Value);
                if (ti == null)
                    return new XmlRpcStruct { { "result", false }, { "result_text", "Topic Not Found".ToBytes() } };

                var post = new AFTForumController().GetForumPost(portalId, forumModuleId, ti.ContentId);
                if (post == null)
                    return new XmlRpcStruct { { "result", false }, { "result_text", "Topic Post Not Found".ToBytes() } };

                forumId = post.ForumId;
            }

            var subscriptionType = unsubscribe ? SubscriptionTypes.Disabled : SubscriptionTypes.Instant;

            var sub = new SubscriptionController().Subscription_Update(portalId, forumModuleId, forumId.Value, topicId.HasValue ? topicId.Value : -1, (int)subscriptionType, aftContext.UserId, aftContext.ForumUser.UserRoles);

            var result = (sub >= 0) ? "1" : "0";

            return new XmlRpcStruct
            {
                {"result", result},
                {"result_text", string.Empty.ToBytes()}, 
            };
        }
        private XmlRpcStruct GetSubscribedTopics(int startIndex, int endIndex)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var userId = aftContext.UserId;

            // Build a list of forums the user has access to
            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, portalId, forumModuleId, "CanRead");

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var profilePath = string.Format("{0}://{1}{2}", Context.Request.Url.Scheme, Context.Request.Url.Host, VirtualPathUtility.ToAbsolute("~/profilepic.ashx"));

            var maxRows = endIndex + 1 - startIndex;

            var subscribedTopics = fc.GetSubscribedTopics(portalId, forumModuleId, userId, forumIds, startIndex, maxRows).ToList();



            return new XmlRpcStruct
                       {
                           {"total_topic_num", subscribedTopics.Count > 0 ? subscribedTopics[0].TopicCount : 0},
                           {"topics", subscribedTopics.Select(t => new ExtendedTopicStructure{ 
                                                   TopicId = t.TopicId.ToString(),
                                                   AuthorAvatarUrl = string.Format("{0}?userId={1}&w=64&h=64", profilePath, t.LastReplyAuthorId),
                                                   AuthorName = GetLastReplyAuthorName(mainSettings, t).ToBytes(),
                                                   AuthorId = t.LastReplyAuthorId.ToString(),
                                                   ForumId = t.ForumId.ToString(),
                                                   ForumName = t.ForumName.ToBytes(),
                                                   HasNewPosts =  (t.LastReplyId < 0 && t.TopicId > t.UserLastTopicRead) || t.LastReplyId > t.UserLastReplyRead,
                                                   IsLocked = t.IsLocked,
                                                   ReplyCount = t.ReplyCount,
                                                   Summary = GetSummary(null, t.LastReplyBody).ToBytes(),
                                                   ViewCount = t.ViewCount,
                                                   DateCreated = t.LastReplyDate,
                                                   Title = HttpUtility.HtmlDecode(t.Subject + string.Empty).ToBytes()
                                               }).ToArray()}
                       };
        }
        private XmlRpcStruct GetUser(string username, int userId)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            // Not fully implemented...  Disable for now.

            // for our purposes, we ignore the username and require userId
            // If we don't have a userid, pass back a anonymous user object
            if (true || userId <= 0)
            {
                return new XmlRpcStruct
                           {
                               { "user_id", userId.ToString() },
                               { "user_name", username.ToBytes() },
                               { "post_count", 1 }
                           };
            }

            var portalId = aftContext.Module.PortalID;
            var currentUserId = aftContext.UserId;

            var fc = new AFTForumController();

            var user = fc.GetUser(portalId, userId, currentUserId);

            const bool allowPM = false; //TODO : Tie in with PM's
            const bool acceptFollow = false;

            if (user == null)
            {
                return new XmlRpcStruct
                           {
                               { "user_id", userId.ToString() },
                               { "user_name", username.ToBytes() },
                               { "post_count", 1 }
                           };
            }

            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;
            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            return new XmlRpcStruct
                           {
                               { "user_id", userId.ToString() },
                               { "user_name", GetUserName(mainSettings, user).ToBytes() },
                               { "post_count", user.PostCount },
                               { "reg_time", user.DateCreated },
                               { "last_activity_date", user.DateLastActivity },
                               { "is_online", user.IsUserOnline },
                               { "accept_pm", allowPM },
                               { "i_follow_u", user.Following },
                               { "u_follow_me", user.IsFollower },
                               { "accept_follow", acceptFollow },
                               { "following_count", user.FollowingCount },
                               { "follower", user.FollowerCount },
                               { "display_text", user.UserCaption.ToBytes() },
                               { "icon_url", GetAvatarUrl(userId) }, 
                           };
        }
        private XmlRpcStruct GetQuote(string postIds)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;

            var fc = new AFTForumController();

            // Load our forum settings
            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            // Get our quote template info
            var postedByTemplate = Utilities.GetSharedResource("[RESX:PostedBy]") + " {0} {1} {2}";
            var sharedOnText = Utilities.GetSharedResource("On.Text");

            var contentIds = postIds.Split('-').Select(int.Parse).ToList();

            if (contentIds.Count > 25) // Let's be reasonable
                throw new XmlRpcFaultException(100, "Bad Request");


            var postContent = new StringBuilder();

            foreach (var contentId in contentIds)
            {
                // Retrieve the forum post
                var forumPost = fc.GetForumPost(portalId, forumModuleId, contentId);

                if (forumPost == null)
                    throw new XmlRpcFaultException(100, "Bad Request");

                // Verify read permissions - Need to do this for every content id as we can not assume they are all from the same forum (even though they probably should be)
                var fp = fc.GetForumPermissions(forumPost.ForumId);

                if (!ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanRead))
                    continue;


                // Build our sanitized quote
                var postedBy = string.Format(postedByTemplate, GetAuthorName(mainSettings, forumPost), sharedOnText,
                                             GetServerDateTime(mainSettings, forumPost.DateCreated));

                postContent.Append(HtmlToTapatalkQuote(postedBy, forumPost.Body));
                postContent.Append("\r\n");
                // add the result

            }

            return new XmlRpcStruct
            {
                {"post_id", postIds},
                {"post_title", string.Empty.ToBytes()},
                {"post_content", postContent.ToString().ToBytes()}
            };
        }
        private ForumStructure[] GetForums(bool includeDescription)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var fc = new AFTForumController();
            var forumIds = fc.GetForumsForUser(aftContext.ForumUser.UserRoles, aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, "CanRead");
            var forumTable = fc.GetForumView(aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, aftContext.UserId, aftContext.ForumUser.IsSuperUser, forumIds);
            var forumSubscriptions = fc.GetSubscriptionsForUser(aftContext.ModuleSettings.ForumModuleId, aftContext.UserId, null, 0).ToList();

            var result = new List<ForumStructure>();

            // Note that all the fields in the DataTable are strings if they come back from the cache, so they have to be converted appropriately.

            // Get the distict list of groups
            var groups = forumTable.AsEnumerable()
                .Select(r => new
                {
                    ID = Convert.ToInt32(r["ForumGroupId"]),
                    Name = r["GroupName"].ToString(),
                    SortOrder = Convert.ToInt32(r["GroupSort"]),
                    Active = Convert.ToBoolean(r["GroupActive"])
                }).Distinct().Where(o => o.Active).OrderBy(o => o.SortOrder);

            // Get all forums the user can read
            var visibleForums = forumTable.AsEnumerable()
                .Select(f => new
                {
                    ID = Convert.ToInt32(f["ForumId"]),
                    ForumGroupId = Convert.ToInt32(f["ForumGroupId"]),
                    Name = f["ForumName"].ToString(),
                    Description = f["ForumDesc"].ToString(),
                    ParentForumId = Convert.ToInt32(f["ParentForumId"]),
                    ReadRoles = f["CanRead"].ToString(),
                    SubscribeRoles = f["CanSubscribe"].ToString(),
                    LastRead = Convert.ToDateTime(f["LastRead"]),
                    LastPostDate = Convert.ToDateTime(f["LastPostDate"]),
                    SortOrder = Convert.ToInt32(f["ForumSort"]),
                    Active = Convert.ToBoolean(f["ForumActive"])
                })
                .Where(o => o.Active && ActiveForums.Permissions.HasPerm(o.ReadRoles, aftContext.ForumUser.UserRoles))
                .OrderBy(o => o.SortOrder).ToList();

            foreach (var group in groups)
            {
                // Find any root level forums for this group
                var groupForums = visibleForums.Where(vf => vf.ParentForumId == 0 && vf.ForumGroupId == group.ID).ToList();

                if (!groupForums.Any())
                    continue;

                // Create the structure to represent the group
                var groupStructure = new ForumStructure()
                {
                    ForumId = "G" + group.ID.ToString(), // Append G to distinguish between forums and groups with the same id.
                    Name = group.Name.ToBytes(),
                    Description = null,
                    ParentId = "-1",
                    LogoUrl = null,
                    HasNewPosts = false,
                    IsProtected = false,
                    IsSubscribed = false,
                    CanSubscribe = false,
                    Url = null,
                    IsGroup = true,
                };

                // Add the Child Forums
                var groupChildren = new List<ForumStructure>();
                foreach (var groupForum in groupForums)
                {
                    var forumStructure = new ForumStructure
                    {
                        ForumId = groupForum.ID.ToString(),
                        Name = Utilities.StripHTMLTag(groupForum.Name).ToBytes(),
                        Description = includeDescription ? Utilities.StripHTMLTag(groupForum.Description).ToBytes() : string.Empty.ToBytes(),
                        ParentId = 'G' + group.ID.ToString(),
                        LogoUrl = null,
                        HasNewPosts = aftContext.UserId > 0 && groupForum.LastPostDate > groupForum.LastRead,
                        IsProtected = false,
                        IsSubscribed = forumSubscriptions.Any(fs => fs.ForumId == groupForum.ID),
                        CanSubscribe = ActiveForums.Permissions.HasPerm(groupForum.SubscribeRoles, aftContext.ForumUser.UserRoles),
                        Url = null,
                        IsGroup = false
                    };

                    // Add any sub-forums

                    var subForums = visibleForums.Where(vf => vf.ParentForumId == groupForum.ID).ToList();

                    if (subForums.Any())
                    {
                        var forumChildren = new List<ForumStructure>();

                        foreach (var subForum in subForums)
                        {
                            forumChildren.Add(new ForumStructure
                            {
                                ForumId = subForum.ID.ToString(),
                                Name = Utilities.StripHTMLTag(subForum.Name).ToBytes(),
                                Description = includeDescription ? Utilities.StripHTMLTag(subForum.Description).ToBytes() : String.Empty.ToBytes(),
                                ParentId = groupForum.ID.ToString(),
                                LogoUrl = null,
                                HasNewPosts = aftContext.UserId > 0 && subForum.LastPostDate > subForum.LastRead,
                                IsProtected = false,
                                IsSubscribed = forumSubscriptions.Any(fs => fs.ForumId == subForum.ID),
                                CanSubscribe = ActiveForums.Permissions.HasPerm(subForum.SubscribeRoles, aftContext.ForumUser.UserRoles),
                                Url = null,
                                IsGroup = false
                            });
                        }

                        forumStructure.Children = forumChildren.ToArray();
                    }

                    groupChildren.Add(forumStructure);
                }

                groupStructure.Children = groupChildren.ToArray();

                result.Add(groupStructure);
            }

            return result.ToArray();
        }
        private PostListStructure GetThreadByPost(int postId, int postsPerRequest, bool returnHtml)
        {
            // PostId = ContentId for our purposes

            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            var postIndexResult = new AFTForumController().GetForumPostIndex(postId);

            if (postIndexResult == null)
                throw new XmlRpcFaultException(100, "Post Not Found");

            var pageIndex = (postIndexResult.RowIndex - 1) / postsPerRequest;
            var startIndex = pageIndex * postsPerRequest;
            var endIndex = startIndex + postsPerRequest - 1;

            var result = GetThread(postIndexResult.TopicId, startIndex, endIndex, returnHtml);

            // Post index is zero base, so we need to add 1 before sending it to Tapatalk

            return new PostListPlusPositionStructure(result, postIndexResult.RowIndex + 1); //result;
        }
        private PostListStructure GetThread(int topicId, int startIndex, int endIndex, bool returnHtml)
        {
            var aftContext = ActiveForumsTapatalkModuleContext.Create(Context);

            if (aftContext == null || aftContext.Module == null)
                throw new XmlRpcFaultException(100, "Invalid Context");

            Context.Response.AddHeader("Mobiquo_is_login", aftContext.UserId > 0 ? "true" : "false");

            var portalId = aftContext.Module.PortalID;
            var forumModuleId = aftContext.ModuleSettings.ForumModuleId;

            var fc = new AFTForumController();

            var forumId = fc.GetTopicForumId(topicId);

            if (forumId <= 0)
                throw new XmlRpcFaultException(100, "Invalid Topic");

            var fp = fc.GetForumPermissions(forumId);

            if (!ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanRead))
                throw new XmlRpcFaultException(100, "No Read Permissions");

            var maxRows = endIndex + 1 - startIndex;

            var forumPostSummary = fc.GetForumPostSummary(aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, forumId, topicId, aftContext.UserId);
            var forumPosts = fc.GetForumPosts(aftContext.Module.PortalID, aftContext.ModuleSettings.ForumModuleId, forumId, topicId, aftContext.UserId, startIndex, maxRows);

            var breadCrumbs = new List<BreadcrumbStructure>
                                  {
                                      new BreadcrumbStructure
                                          {
                                              ForumId = 'G' + forumPostSummary.ForumGroupId.ToString(),
                                              IsCategory = true,
                                              Name = forumPostSummary.GroupName.ToBytes()
                                          },
                                  };

            // If we're in a sub forum, add the parent to the breadcrumb
            if (forumPostSummary.ParentForumId > 0)
                breadCrumbs.Add(new BreadcrumbStructure
                {
                    ForumId = forumPostSummary.ParentForumId.ToString(),
                    IsCategory = false,
                    Name = forumPostSummary.ParentForumName.ToBytes()
                });

            breadCrumbs.Add(new BreadcrumbStructure
            {
                ForumId = forumId.ToString(),
                IsCategory = false,
                Name = forumPostSummary.ForumName.ToBytes()
            });

            var mainSettings = new SettingsInfo { MainSettings = new Entities.Modules.ModuleController().GetModuleSettings(forumModuleId) };

            var profilePath = string.Format("{0}://{1}{2}", Context.Request.Url.Scheme, Context.Request.Url.Host, VirtualPathUtility.ToAbsolute("~/profilepic.ashx"));

            var result = new PostListStructure
                             {
                                 PostCount = forumPostSummary.ReplyCount + 1,
                                 CanReply = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanReply),
                                 CanSubscribe = ActiveForums.Permissions.HasPerm(aftContext.ForumUser.UserRoles, fp.CanSubscribe),
                                 ForumId = forumId,
                                 ForumName = forumPostSummary.ForumName.ToBytes(),
                                 IsLocked = forumPostSummary.IsLocked,
                                 IsSubscribed = forumPostSummary.SubscriptionType > 0,
                                 Subject = forumPostSummary.Subject.ToBytes(),
                                 TopicId = topicId,
                                 Posts = forumPosts.Select(p => new PostStructure
                                    {
                                        PostID = p.ContentId.ToString(),
                                        AuthorAvatarUrl = string.Format("{0}?userId={1}&w=64&h=64", profilePath, p.AuthorId),
                                        AuthorName = GetAuthorName(mainSettings, p).ToBytes(),
                                        AuthorId = p.AuthorId.ToString(),
                                        Body = HtmlToTapatalk(p.Body, returnHtml).ToBytes(),
                                        CanEdit = false, // TODO: Fix this
                                        IsOnline = p.IsUserOnline,
                                        PostDate = p.DateCreated,
                                        Subject = p.Subject.ToBytes()
                                    }).ToArray(),
                                 Breadcrumbs = breadCrumbs.ToArray()

                             };

            return result;
        }