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

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

namespace CommunityServer.Components.SearchBarrel
{
	/// <summary>
	/// Enables auto indexing of forum posts
	/// </summary>
	public class ForumsSearchJob : SearchJob
	{
		public ForumsSearchJob()
		{
		}

        /// <summary>
        /// Indexes posts on the specified SettingsID
        /// </summary>
        public override void IndexPosts(int setSize, int settingsID)
        {                     
            ForumDataProvider fdp = ForumDataProvider.Instance();
            PostSet postSet =  fdp.SearchReindexPosts(setSize, settingsID);
            
            foreach (Post post in postSet.Posts) 
            {
                Hashtable words = new Hashtable();
                int totalBodyWords = 0;

                // Process words in the forum name
                //
                // TDD 11/05/2004
                // Since we're running this in a background thread, the Section property of the post can not be resolved
                // because we don't have a proper context. We also cant get the Section from the PostID because Sections
                // doesn't have a method to get a Section and we can't assume that we're indexing just forum posts.
                //
                // In the future this will need to be improved by having each application define it search component and
                // loading that component up based on the application type of the forum.
                //words = Index(post.Section.Name, words, WordLocation.Forum);

                // Process the authors name
                //
                words = Index(post.Username, words, WordLocation.Author, settingsID);

                // Process the post subject
                //
                words = Index(post.Subject, words, WordLocation.Subject,settingsID);

                // Process the post body
                //
                words = Index(post.Body, words, WordLocation.Body, settingsID);

                // Get a count of the total words in the body
                //
                totalBodyWords = SearchTerms.CleanSearchTerms(post.Body).Length;

                InsertIntoSearchBarrel(words, post, settingsID, totalBodyWords);

            }
        }

        /// <summary>
        /// Scores a forum post
        /// </summary>
        /// <param name="word"></param>
        /// <param name="post"></param>
        /// <param name="totalBodyWords"></param>
        /// <returns></returns>
        protected override double CalculateWordRank(Word word, Post post, int totalBodyWords)
        {
            int wordOccurrence = 0;
            double replyWeight = 0;
            double wordCount = 0;
            int locked = 0;
            int pinned = 0;
            double rating = 0;
            int totalRatings = 0;

            // Word weighting:
            // ============================
            // Word Occurence:      20
            // Replies:             20
            // Total words in post: 20
            // Locked:               5
            // Pinned:               5
            // Word in Forum title:  5
            // Word in Subject:     10
            // Rating:				15
            //                    ----
            // Max score:          100

            // Assign a score for how many times the word occurs in the post
            //
            wordOccurrence = word.Occurence * 2;
            if (wordOccurrence > 20)
                wordOccurrence = 20;

            // Calculate the score for replies
            //
            if ( (post.PostLevel == 1) && (post.Replies == 0)) 
            {
            
                replyWeight = 0;  // A post with no replies

            } 
            else 
            {

                replyWeight = ( (post.PostLevel - (post.Replies * 0.01)) / (post.PostLevel + post.Replies) ) * 20f;

                // If less than 0, weighting is 0
                if (replyWeight < 0)
                    replyWeight = 0;

            }

            // Calculate a score for the count of total words in the post
            //
            if (totalBodyWords > 65)
                wordCount = 20;
            else
                wordCount = (totalBodyWords / 65f) * 20f;

            // Calculate a score if the post is locked or pinned
            //
            if (post.IsLocked)
                locked = 5;
            if (post is IThread) 
            {
                IThread thread = (IThread) post;

                if ( thread.IsAnnouncement)
                    pinned = 5;

                // Handle ratings
                if ( thread.TotalRatings > 0 ) 
                {

                    // 5 points for rating greater than 10 ratings
                    if (thread.TotalRatings > 25)
                        totalRatings = 5;
                    else if (thread.TotalRatings > 20)
                        totalRatings = 4;
                    else if (thread.TotalRatings > 15)
                        totalRatings = 3;
                    else if (thread.TotalRatings > 10)
                        totalRatings = 2;
                    else
                        totalRatings = 1;

                    rating = (thread.RatingAverage * 2);

                }
            }

            // Calculate the final weight of the word
            //
            return (wordOccurrence + replyWeight + word.OccurenceWeight + wordCount + locked + pinned + totalRatings + rating) / 100f;
        }

	}
}
