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

using System;
using System.Collections;
using System.Drawing;
using System.Text.RegularExpressions;
using CommunityServer.Components;

namespace CommunityServer.Discussions.Components
{
	/// <summary>
	/// Summary description for ForumPost.
	/// </summary>
	public class ForumPost : Post
	{
		public ForumPost()
		{
			
		}

        #region Section Implementation
        Section section;

        public override Section Section
        {
            get 
            {
                if (section == null) 
                {
                    if (this.SectionID >= 0)
                        section = Forums.GetForum(this.SectionID);
                }

                return section;
            }
            set 
            {
                section = value;
            }
        }
        #endregion

		public Forum Forum {
			get {
				return (Forum) this.Section;
			}
			set {
				this.Section = value;
			}
		}

        #region GetBodySummary
        // *********************************************************************
        //
        //  BodySummary
        //
        /// <summary>
        /// Returns a summarized version of the post body
        /// </summary>
        //
        // ********************************************************************/
        public string GetBodySummary (int size, string terms, Color color, Color bgColor) 
        {
            string[] highlightWords = terms.Split(' ');

            return GetBodySummary (size, highlightWords, color, bgColor);
        }

        public string GetBodySummary(int size, string[] highlightWords, Color color, Color bgColor) 
        {
			// EAD 6/27/04: New function I wrote a month ago to strip all
			// tags out and replace with line breaks.  In this case, we need to
			// insert <br />s inplace of line breaks so it looks somewhat neat.
			//
			// LN 6/23/04 : Do not Html encode the body
			// postBody = Globals.HtmlEncode(Transforms.StripHtmlXmlTags(postBody));
			// postBody = Transforms.StripHtmlXmlTags(postBody);
			string postBody = Formatter.StripAllTags(FormattedBody);

            // We only want to display some of the body
            //
            if (size > 0 && postBody.Length > size) 
            {
                int whitespace = 0;
                // Clip the body
                postBody = postBody.Substring(0, size);

                // Find the last occurence of a space
                whitespace = postBody.LastIndexOf(" ");

                if( whitespace == -1 )
                    whitespace = size;
				
                // Rebuild postBody string
                postBody = postBody.Substring(0, whitespace) + " ...";
            }

			// Do any word highlighting
            //
            if (highlightWords.Length > 0 ) 
            {
                string delimitedString;

                // Split and delimit string
                //
                delimitedString = Transforms.ToDelimitedString(highlightWords, "|");

                // TDD 7/19/2004
                // this string is used as the regex pattern. if it contains special characters like (,* $ it
                // throw an error since these are special instruction characters to Regex. We must escape these
                // special characters if they are used as search strings.
                delimitedString = Regex.Escape( delimitedString );
                // Perform replacement
                //
                postBody = Regex.Replace(postBody, delimitedString, "<span style=\"color:" + color.Name + ";background-color:" + bgColor.Name + "\"><b>$0</b></span>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
            }

            return postBody;
        }
        #endregion

        public override String Username 
        {
            get 
            { 
                if (PostNeedsIgnoredScrubbing())
                    return ResourceManager.GetString("IgnoredPost_Username");
                else
                    return base.Username; 
            }
            set { base.Username = value; }			
        }

        public override String Body 
        {
            get 
            { 
                if (PostNeedsIgnoredScrubbing())
                    return ResourceManager.GetString("IgnoredPost_Body");
                else
                    return base.Body; 
            }
            set 
            { 
                base.Body = value; 
            }
        }

        public override string EditNotes 
        {
            get 
            {
                if (PostNeedsIgnoredScrubbing())
                    return String.Empty;
                else
                    return base.EditNotes;
            }
            set 
            {
                base.EditNotes = value;
            }
        }

        // *********************************************************************
        //
        //  FormattedBody
        //
        /// <summary>
        /// Returns a pre-formatted version of the body of the post.
        /// </summary>
        /// <remarks>
        /// The FormattedBody of the post is stored in a pre-formatted HTML.
        /// </remarks>
        //
        // ********************************************************************/
        public override String FormattedBody 
        {
            get 
            { 
                if (PostNeedsIgnoredScrubbing())
                    return ResourceManager.GetString("IgnoredPost_Body");
                else
                    return base.FormattedBody; 
            }
            set 
            { 
                base.FormattedBody = value; 
            }
        }
        public override String Subject 
        {
            get 
            { 
                if (PostNeedsIgnoredScrubbing())
                    return ResourceManager.GetString("IgnoredPost_Subject");

                return base.Subject; 
            }
            set 
            { 
                base.Subject = value; 
            }
        }

        public override bool IsLocked 
        {
            get { return LockIgnoredPost(base.IsLocked); }
            
            set 
            {
                base.IsLocked = value;
            }
        }


        public ForumPostType ForumPostType
        {
            get {return (ForumPostType)ApplicationPostTypeValue;}
            set {ApplicationPostTypeValue = (int)value;}
        }

        string threadStarterUsername = "";
        DateTime threadStartDate = DateTime.MinValue;

        /// <summary>
        /// Acts as a bag for different post attributes values.
        /// This should not be used directly. It's scope is to be used by
        /// other properties as mask to determine if their values are set.
        /// </summary>
        public PostConfiguration PostConfiguration 
        {
            get { return (PostConfiguration)this.PostConfigurationValue; }
            set { this.PostConfigurationValue = (int)value; }
        }

        /// <summary>
        /// Specifies if this post should be seen as anonymous by
        /// the user who posted it.
        /// </summary>
        public bool IsAnonymousPost 
        {
            get 
            { 
                // We have to use integral types
                return IsPostConfigurationValueSet( (int) PostConfiguration.IsAnonymousPost );
            }
            set 
            {
                if (value == true)
                    SetPostConfigurationValueValue( (int) PostConfiguration.IsAnonymousPost, false );
                else 
                {
                    SetPostConfigurationValueValue( (int) PostConfiguration.IsAnonymousPost, true );
                }
            }
        }

        /// <summary>
        /// Specifies if the post has been made by a user who have been flagged as ignored 
        /// by the moderators or administrators.
        /// </summary>
        public bool IsIgnoredPost 
        {
            get 
            { 
                // We have to use integral types
                return IsPostConfigurationValueSet( (int) PostConfiguration.IsIgnoredPost );
            }
            set 
            {
                if (value == true)
                    SetPostConfigurationValueValue( (int) PostConfiguration.IsIgnoredPost, false );
                else 
                {
                    SetPostConfigurationValueValue( (int) PostConfiguration.IsIgnoredPost, true );
                }
            }
        }

        public bool PostShouldBeIgnored
        {
            get {return this.PostNeedsIgnoredScrubbing();}
        }

        /// <summary>
        /// The user name that started the thread this post belongs to.
        /// </summary>
        public string ThreadStarterUsername
        {
            get { return threadStarterUsername; }
            set { threadStarterUsername = value; }
        }

        /// <summary>
        /// The date at thread starter post has been published.
        /// </summary>
        public DateTime ThreadStartDate
        {
            get { return threadStartDate; }
            set { threadStartDate = value; }
        }

		private string[] categories;

		/// <summary>
		/// list of categories this post was made to
		/// </summary>
		public string[] Categories
		{
			get{return categories;}
			set{categories = value;}
		}

        #region Helpers
        /// <summary>
        /// Set or erase provided <see cref="PostConfiguration"/> value from PostSetting mask.
        /// </summary>
        private void SetPostConfigurationValueValue (int theValue, bool erase) 
        {
            if (erase) 
            {
                if (IsPostConfigurationValueSet( theValue ))
                    this.PostConfigurationValue ^= theValue; // erase the value through XOR
            }
            else 
            {
                this.PostConfigurationValue |= theValue; // set the value
            }
        }

        /// <summary>
        /// Check if provided value is set in the mask.
        /// </summary>
        private bool IsPostConfigurationValueSet (int theValue) 
        {
            return ( (this.PostConfigurationValue & theValue) == theValue ) ? true : false;
        }

        private bool LockIgnoredPost(bool isLocked)
        {
            bool lockPost = isLocked;

            // If the post isn't already locked, check to see if
            // it's an ignored post that needs to be locked. 
            if (!lockPost)
            {
                lockPost = PostNeedsIgnoredScrubbing();
            }
			
            return lockPost;
        }

        /// <summary>
        /// Checks to see if this post is an ignored post, and then checks
        /// to see who the current user is.  If the current user is a
        /// forum administrator, a moderator, or the author of the post,
        /// then the method returns false.  If the post is an ignored post 
        /// and the user is not one of the above, the method returns true. 
        /// </summary>
        private bool PostNeedsIgnoredScrubbing()
        {
            bool needsScrubbing = false;
            User currentUser = CSContext.Current.User;
	
            if (this.IsIgnoredPost && 
                currentUser.Username != base.Username)
            {
                if (!currentUser.IsForumAdministrator
                    || !currentUser.IsModerator)
                {
                    needsScrubbing = true;  
											 
                }
            }
            return needsScrubbing;
        }

        #endregion

	}
}
