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

using System;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;

using CommunityServer.Blogs.Components;
using CommunityServer.Components;

namespace CommunityServer.Blogs.Components
{
    /// <summary>
    /// Summary description for TrackBackHandler.
    /// </summary>
    public class TrackBackHandler : IHttpHandler
    {
        public TrackBackHandler() 
        {
        }
	
        public void ProcessRequest(HttpContext context)
        {

            context.Response.ContentType="text/xml" ;
			CSContext cntx = CSContext.Current;


            User user = cntx.User;
            int postId = 0 ;
            try 
            {
                postId = int.Parse(context.Request.QueryString["postid"]) ;
            }
            catch 
            {
                trackbackResponse (context, 1, "EntryID is invalid or missing" ) ;
            }


            if ( context.Request.HttpMethod == "POST" )
            {
                string title     = safeParam(context,"title");
                string excerpt   = safeParam(context,"excerpt");
                string url       = safeParam(context,"url");
                string blog_name = safeParam(context,"blog_name");

                if(!Globals.IsNullorEmpty(excerpt))
                    excerpt = Formatter.RemoveHtml(excerpt,250);

				try
				{
					// is the url valid ?
					if ( url == "" )
					{
						trackbackResponse (context, 1, "no url parameter found, please try harder!") ;
					}
	
					string pageTitle = null;
                
					WeblogPost trackedEntry = WeblogPosts.GetPost(postId,false,true,false);

                
					if(trackedEntry == null)
					{
						trackbackResponse (context, 2, "The link does not exist" ) ;
						return;
					}
                
					Weblog wl = trackedEntry.Section as Weblog;

					Permissions.AccessCheck(wl,Permission.View, user );

					if(!wl.ValidateTrackBacks(trackedEntry))
					{
						trackbackResponse (context, 2, "Trackbacks are not enabled" ) ;
						return;
					}

					if(!IsNewTrackBack(trackedEntry,url))
					{
						trackbackResponse (context, 2, "Trackbacks already exists" ) ;
						return;
                    
					}
				
					if (!SourceContainsTarget(url, Globals.FullPath(BlogUrls.Instance().Post(trackedEntry, wl)), out pageTitle))
					{
						trackbackResponse (context, 2, "Sorry couldn't find a relevant link in " + url ) ;
					}

                
					WeblogPost entry = new WeblogPost();
					entry.BlogPostType = BlogPostType.Trackback;
					entry.SectionID = wl.SectionID;
					entry.ParentID = postId;
					entry.Subject = title;
					entry.TitleUrl = url;
					entry.TrackBackName = blog_name;
					entry.Body = excerpt;
					entry.IsApproved = true;
					entry.PostDate = DateTime.Now;
					entry.UserTime = DateTime.Now;

					int trackbackPostID;
					BlogPostResults status = WeblogPosts.Add(entry, user, out trackbackPostID);

					if (status != BlogPostResults.Success)
						trackbackResponse(context, 2, "Failed to save Trackback." );
				
					// Log success message to EventLog
					string message = String.Format("Trackback request received by Community Server for PostID {0} and successfully saved as PostID {1}.", postId, trackbackPostID);
					EventLogs.Info(message, "Weblogs", 300, cntx.SettingsID);

				}
				catch (System.Threading.ThreadAbortException) {}
				catch (System.Exception ex)
				{
					if (ex.Message != null)
                        trackbackResponse (context, 0, string.Format("Error occurred while processing Trackback: {0}", ex.Message));
					else
						trackbackResponse (context, 0, "Unknown error occurred while processing Trackback.");
				}
				
            }
            else
            {

                WeblogPost entry = WeblogPosts.GetPost(postId,false,true,false);
                Weblog wl = entry.Section as Weblog;

                Permissions.AccessCheck(wl,Permission.View, user);

                XmlTextWriter w = new XmlTextWriter(context.Response.Output) ;
                w.Formatting = Formatting.Indented;

                w.WriteStartDocument() ;
                w.WriteStartElement("response") ;
                w.WriteElementString("error", "0") ;
                w.WriteStartElement("rss") ;
                w.WriteAttributeString("version", "0.91") ;
                w.WriteStartElement("channel") ;
                w.WriteElementString("title", entry.Subject );
                w.WriteElementString("link", BlogUrls.Instance().TrackbackPingUrl(wl.ApplicationKey, postId));
                w.WriteElementString("description", "" ) ;
                w.WriteElementString("language", "en-us" ) ;

                w.WriteEndElement() ; // channel
                w.WriteEndElement() ; // rss 
                w.WriteEndElement() ; // response
                w.WriteEndDocument() ;
		
            }

        }

        public bool IsReusable
        {
            get { return false; }
        }

        private void trackbackResponse(HttpContext context, int errNum, string errText)
        {
			// Log trackback failure messae to the EventLog
			string message = String.Format("Trackback request received by Community Server but failed due to one or more reasons. The request URL was [{0}]. Error message returned was: {1}.", context.Request.RawUrl, errText);
			EventLogs.Warn(message, "Weblogs", 300, CSContext.Current.SettingsID);
			
			XmlDocument d = new XmlDocument() ;
            XmlElement root = d.CreateElement("response") ;
            d.AppendChild(root) ;
            XmlElement er = d.CreateElement("error") ;
            root.AppendChild(er) ;
            er.AppendChild(d.CreateTextNode(errNum.ToString())) ;
            if ( errText != "" )
            {
                XmlElement msg = d.CreateElement("message") ;
                root.AppendChild(msg) ;
                msg.AppendChild(d.CreateTextNode(errText)) ;
            }
            d.Save ( context.Response.Output ) ;
            context.Response.End();
        }

        private string safeParam(HttpContext context,string pName)
        {
            if ( context.Request.Form[pName] != null )
                return context.Request.Form[pName];
            return  string.Empty;
        }

        public static  bool SourceContainsTarget(string sURI, string tURI, out string pageTitle)
        {
            pageTitle = string.Empty;
            string page = CSRequest.GetPageText(sURI, tURI);

			// Look for a matching path & query only. Skip the host/port part of the URI because
			//	the body may be using relative URLS for intra-site links.
			Uri target = new Uri(tURI);
            if (page == null ||  page.IndexOf(target.PathAndQuery) < 0 )
                return false ;
			
            string pat = @"<head.*?>.*<title.*?>(.*)</title.*?>.*</head.*?>" ;
            Regex reg = new Regex(pat, RegexOptions.IgnoreCase | RegexOptions.Singleline  ) ;
            Match m = reg.Match(page) ;
            if ( m.Success )
            {
                pageTitle = m.Result("$1") ;
                return true ;
            }
 
            return false ;
        }

        private static bool IsNewTrackBack(WeblogPost post, string trackbackUrl)
        {
            BlogThreadQuery query = new BlogThreadQuery();
            query.SectionID = post.SectionID;
            query.IncludeCategories = false;
            query.PostID = post.PostID;
            query.ReturnFullThread = true;
            
            PostSet ps = WeblogPosts.GetPosts(query,false);
            ps.Organize();

            foreach(WeblogPost p in ps.Replies)
            {
                if ( (string.Compare(trackbackUrl,p.TitleUrl,true) == 0) && (p.BlogPostType == BlogPostType.Trackback) )
                    return false;
            }

            return true;
        }
    }
}

