//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Web;
using System.Collections;
using CommunityServer;
using CommunityServer.Components;
using CommunityServer.Discussions.Components;

namespace CommunityServer.Discussions.Controls {

    // *********************************************************************
    //  Moderate
    //
    /// <summary>
    /// This class contains methods that are helpful for moderating posts.
    /// </summary>
    /// 
    // ********************************************************************/ 
    public class Moderate {

        public static PostSet GetPosts(int forumID, int pageIndex, int pageSize, int sortBy, int sortOrder) {

            ForumDataProvider dp = ForumDataProvider.Instance();

            return dp.GetPostsToModerate(forumID, pageIndex, pageSize, sortBy, sortOrder, CSContext.Current.User.UserID, true);

        }

        public static void TogglePostSettings (ModeratePostSetting setting, ForumPost post, int moderatorID) {

            ForumDataProvider dp = ForumDataProvider.Instance();

            dp.TogglePostSettings(setting, post, moderatorID);
        }

        public static void ToggleUserSettings (ModerateUserSetting setting, User user, int moderatorID) {
            ForumDataProvider dp = ForumDataProvider.Instance();

            dp.ToggleUserSettings(setting, user, moderatorID);

        }

        // *********************************************************************
        //  CanEditPost
        //
        /// <summary>
        /// This method determines whether or not a user can edit a particular post.
        /// </summary>
        /// <param name="strUsername">The username of the user who you wish to know if he can edit
        /// the post.</param>
        /// <param name="iPostID">To post you wish to know if the user can edit.</param>
        /// <returns>A boolean value: true if the user can edit the post, false otherwise.</returns>
        /// <remarks>Moderators can edit posts that are still waiting for approval in the forum(s) they 
        /// are cleared to moderate.  Forum administrators may edit any post, awaiting approval or not,
        /// at any time.</remarks>
        /// 
        // ********************************************************************/ 
        public static bool CanEditPost(String Username, int PostID) {			
            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();

            return dp.CanEditPost(Username, PostID);
        }

        // *********************************************************************
        //  GetForumsByForumGroupId
        //
        /// <summary>
        /// Returns forums requiring moderation that the user can moderate by forum group id
        /// </summary>
        /// <param name="forumGroupID">Id of the forum group to return forums for</param>
        /// <returns>An ArrayList populated with CommunityServer.Components.Forum objects that require moderation.</returns>
        /// <remarks>The Moderate permission on the forum must be set the AccessControlEntry.Allow for the forum to be returned.</remarks>
        // ********************************************************************/ 
        public static ArrayList GetForumsByForumGroupID (int forumGroupID) {

            ArrayList unfilteredForums = Moderate.GetForumsToModerate();
            ArrayList forums = new ArrayList();

            foreach (Forum f in unfilteredForums) {

                if (f.GroupID == forumGroupID)
                    if (f.PostsToModerate > 0)
						if (Permissions.ValidatePermissions(Forums.GetForum(f.SectionID), Permission.Moderate, CSContext.Current.User))
							forums.Add(f);
            }

            return forums;

        }

        #region Forums to Moderate
        public static ArrayList GetForumsToModerate () {
            return GetForumsToModerate(CSContext.Current);
        }

        public static ArrayList GetForumsToModerate (CSContext context) {
            string cacheKey = "ForumsToModerate-" + context.User.UserID;

			if (context.Context.Items[cacheKey] == null)
			{
				ArrayList forums = ForumDataProvider.Instance().GetForumsToModerate(context.User.UserID, ApplicationType.Forum);
				forums = Sections.FilterByLanguage(forums, context);
				context.Context.Items[cacheKey] = forums;
			}

            return (ArrayList) context.Context.Items[cacheKey];
        }
        #endregion

        // *********************************************************************
        //  MovePost
        //
        /// <summary>
        /// Moves a post from one Forum to another.
        /// </summary>
        /// <param name="postID">The post to move.</param>
        /// <param name="moveToForumID">The forum to move the post to.</param>
        /// <param name="movedBy">The user who moved the post.</param>
        /// <param name="sendEmail">Send an email to the post author that the post was moved.</param>
        /// <returns>A MovedPostStatus enumeration value that indicates the status of the attempted move.
        /// This enumeration has four values: NotMoved, MovedButNotApproved, MovedAndApproved and MovedAlreadyApproved.</returns>
        /// <remarks>Moving an unapproved post from one forum to another will approve the post if the user
        /// has Moderate permission on the destination forum.</remarks>
        // ********************************************************************/
        public static MovedPostStatus MovePost(ForumPost post, int moveToForumID, int movedBy, bool sendEmail) {

            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();
            MovedPostStatus status = dp.MovePost(post.PostID, moveToForumID, movedBy);

            if (sendEmail) {
                if (status == MovedPostStatus.MovedAndApproved) {
                    // The post was moved to a new forum and automatically approved
                    Emails.PostMovedAndApproved (post);
                }
                else if (status == MovedPostStatus.MovedAlreadyApproved) {
                    // The post was moved and has previously been approved.
                    Emails.PostMoved(post);
                }
            }

			// Send the thread tracking emails regardless of UI setting
			// UI setting is for thread owner notification
			if ((status == MovedPostStatus.MovedAlreadyApproved) || (status == MovedPostStatus.MovedAndApproved))
				ForumEmails.ForumTracking(post);

            return status;
        }

		public static void UpdatePostParent(ForumPost post, int parentID, int movedBy)
		{
			ForumDataProvider dp = ForumDataProvider.Instance();
			dp.UpdatePostParent(post.PostID, parentID, movedBy);
			CSCache.RemoveByPattern(string.Format("Forum-Posts::P:{0}",Threads.GetThread(post.ThreadID).PostID));
		}

        // *********************************************************************
        //  ThreadSplit
        //
        /// <summary>
        /// Splits a thread into a new thread.
        /// </summary>
        /// <param name="postID">The post to split.</param>
        /// <param name="moveToForumID">The forum to move the post to.</param>
        /// <param name="movedBy">The user who moved the post.</param>
        /// <param name="sendEmail">Send an email to the post author that the post was moved.</param>
        // ********************************************************************/
        public static void ThreadSplit (ForumPost post, int moveToForumID, int movedBy, bool sendEmail) {

            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();
            dp.ThreadSplit(post.PostID, moveToForumID, movedBy);

            if (sendEmail)
                ForumEmails.ForumTracking (post);

            return;
        }

        // *********************************************************************
        //  ThreadJoin
        //
        /// <summary>
        /// Joins two threads into one.
        /// </summary>
        /// <param name="postID">The post to split.</param>
        /// <param name="moveToForumID">The forum to move the post to.</param>
        /// <param name="movedBy">The user who moved the post.</param>
        /// <param name="sendEmail">Send an email to the post author that the post was moved.</param>
        // ********************************************************************/
        public static void ThreadJoin (ForumPost parentThread, ForumPost childThread, int joinedByUserID, bool sendEmail) {

            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();
            dp.ThreadJoin(parentThread.ThreadID, childThread.ThreadID, joinedByUserID);

            if (sendEmail) {
                Emails.ThreadJoined(parentThread, childThread);
            }

            return;
        }

        // *********************************************************************
        //  DeletePost
        //
        /// <summary>
        /// This method deletes a post and all of it's replies by default.
        /// It also includes a reason why the post was deleted.
        /// </summary>
        /// <param name="postID">The post to delete.</param>
        /// <param name="deletedBy">The user who deleted the post.</param>
        /// <param name="reason">The reason why the post was deleted.</param>
        /// <param name="sendEmail">Send an email to the post author that the post was deleted.</param>
        // ********************************************************************/ 
        public static void DeletePost(ForumPost post, User moderatedBy, string reason, bool deleteChildPosts) {
            
            CSEvents.PrePost(post,ObjectState.Delete,ApplicationType.Forum);
            CSEvents.BeforePost(post,ObjectState.Delete,ApplicationType.Forum);

            // Was a reason provided?
            //
            if (reason.Length == 0)
                reason = "No Reason Given.";

            // Create Instance of the CommonDataProvider
            //
            ForumDataProvider dp = ForumDataProvider.Instance();
            dp.ModeratorDeletePost(post.PostID, moderatedBy.UserID, reason, deleteChildPosts);

			// send the email if successful
			//
			Emails.PostRemoved(post, moderatedBy, reason);

            CSCache.RemoveByPattern(string.Format("Forum-Threads::S:{0}",post.SectionID));

            //This will only work for post's at level 1 or 2. need to figure out clean way to find a post's root part
            CSCache.RemoveByPattern(string.Format("Forum-Posts::P{0}",post.PostID));
            if(post.ParentID > 1)
                CSCache.RemoveByPattern(string.Format("Forum-Posts::P{0}",post.ParentID));

            CSEvents.AfterPost(post,ObjectState.Delete,ApplicationType.Forum);
            
        }

        // *********************************************************************
        //  ApprovePost
        //
        /// <summary>
        /// Approves a moderated post.
        /// </summary>
        /// <param name="postID">The post to approve.</param>
        /// <param name="approvedBy">Username approving the post.</param>
        /// <param name="updateUserAsTrusted">Approve the username as no longer requiring moderation</param>
        /// 
        // ********************************************************************/ 
        public static void ApprovePost (ForumPost post, int moderatedBy) {
            bool approved = true;

            // Create Instance of the CommonDataProvider
            //
            ForumDataProvider dp = ForumDataProvider.Instance();

            approved = dp.ApprovePost(post.PostID, moderatedBy);

            // Post hadn't been approved before, send confirmation
            if (approved) {
                ForumEmails.ForumTracking(post);
				Emails.PostApproved(post);
            }

        }
		
        // *********************************************************************
        //  CanModerate
        //
        /// <summary>
        /// Determines whether or not a user can moderate any forums.
        /// </summary>  
        /// <param name="Username">The user who you are interested in determining has moderation
        /// capabilities.</param>
        /// <returns>A boolean, indicating whether or not the user can moderate.</returns>
        /// <remarks>This method does not indicate *what* forums a user can moderate, it just serves to
        /// determine IF a user can moderate at all.</remarks>
        /// 
        // ********************************************************************/ 
        public static bool CheckIfUserIsModerator (int userID, int forumID) {

            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();

            return dp.CheckIfUserIsModerator(userID, forumID);

        }


        // *********************************************************************
        //  GetPostsAwaitingModeration
        //
        /// <summary>
        /// Returns a bool indicating whether the given user has posts to moderate
        /// </summary>
        /// <param name="username">The user name of the individual currently moderating.</param>
        /// 
        // ********************************************************************/ 
        public static bool UserHasPostsAwaitingModeration(String username) {
            // Create Instance of the CommonDataProvider
            ForumDataProvider dp = ForumDataProvider.Instance();

            return dp.UserHasPostsAwaitingModeration(username);
        }

        // *********************************************************************
        //  GetForumModeratorRoles
        //
        /// <summary>
        /// Returns a list of roles that can moderate a particular forum
        /// </summary>
        /// <param name="username">The user name of the individual currently moderating.</param>
        /// 
        // ********************************************************************/ 
        public static ArrayList GetForumModeratorRoles (int forumID) {
            string cacheKey = "ModeratorRoleList-" + forumID.ToString();

            ArrayList roles = CSCache.Get(cacheKey) as ArrayList;
            
            if (roles == null) {
                // Create Instance of the CommonDataProvider
                ForumDataProvider dp = ForumDataProvider.Instance();

                roles = dp.GetForumModeratorRoles(forumID);

                CSCache.Insert(cacheKey,roles,2 * CSCache.MinuteFactor);
            }

            return roles;

        }   
 
		// *********************************************************************
		//  GetQueueStatus
		//
		/// <summary>
		/// Returns the the number of messages in the moderation queue and the length of time the oldest post has been in the queue
		/// </summary>
		/// <param name="sectionID">The sectionID of a specific forum</param>
		/// <param name="userID">The userID of the person currently moderating</param>
		/// <param name="settingsID">The settingsID of the application</param>
		/// 
		// ********************************************************************/ 
		public static ModerationQueueStatus GetQueueStatus(int sectionID, string username)
		{
			ForumDataProvider dp = ForumDataProvider.Instance();

			return dp.GetQueueStatus(sectionID, username);
		}  
    }
}