using System;
using System.IO;
using System.Web.UI;
using Bitrix.CommunicationUtility;
using Bitrix.Components;
using Bitrix.DataLayer;
using Bitrix.DataTypes;
using Bitrix.IO;
using Bitrix.Security;
using Bitrix.Services.Text;
using Bitrix.UI;
using Bitrix.Services;

namespace Bitrix.Blog.Components
{
	public partial class BlogPostComponent : BXComponent
	{
		private string blogSlug;
		private int? postId;
		private ErrorCode fatalError = ErrorCode.FatalComponentNotExecuted;
		private Exception fatalException;
		private bool templateIncluded;
		private BXBlog blog;
		private BXBlogPost post;
		private PostInfo postInfo;
		private BXBlogPostChain processor;
		private int maxWordLength = -1;
		private BXBlogAuthorization auth;
		private BXParamsBag<object> replace;

		public ErrorCode FatalError
		{
			get
			{
				return fatalError;
			}
		}
		public Exception FatalException
		{
			get
			{
				return fatalException;
			}
		}
		public string BlogSlug
		{
			get
			{
				return blogSlug ?? (blogSlug = Parameters.GetString("BlogSlug"));
			}
		}
		public int PostId
		{
			get
			{
				return (postId ?? (postId = Parameters.GetInt("PostId"))).Value;
			}
		}
		public BXBlog Blog
		{
			get
			{
				return blog;
			}
		}
		public PostInfo Post
		{
			get
			{
				return postInfo;
			}
		}
		public int MaxWordLength
		{
			get
			{
				return (maxWordLength != -1) ? maxWordLength : (maxWordLength = Math.Max(0, Parameters.GetInt("MaxWordLength", 15)));
			}
			set
			{
				maxWordLength = Math.Max(0, value);
				Parameters["MaxWordLength"] = maxWordLength.ToString();
			}
		}
		public string PostEditUrlTemplate
		{
			get
			{
				return Parameters.GetString("PostEditUrlTemplate");
			}
			set
			{
				Parameters["PostEditUrlTemplate"] = value;
			}
		}
		public string PostViewUrlTemplate
		{
			get
			{
				return Parameters.GetString("PostViewUrlTemplate");
			}
			set
			{
				Parameters["PostViewUrlTemplate"] = value;
			}
		}
		public string UserProfileUrlTemplate
		{
			get
			{
				return Parameters.GetString("UserProfileUrlTemplate");
			}
			set
			{
				Parameters["UserProfileUrlTemplate"] = value;
			}
		}
		public string BlogUrlTemplate
		{
			get
			{
				return Parameters.GetString("BlogUrlTemplate");
			}
			set
			{
				Parameters["BlogUrlTemplate"] = value;
			}
		}
		public BXBlogAuthorization Auth
		{
			get
			{
				return auth;
			}
		}
		
		internal BXBlogPostChain Processor
		{
			get
			{
				if (processor == null)
				{
					processor = new BXBlogPostChain(blog);
					processor.MaxWordLength = MaxWordLength;
					processor.HideCut = false;
				}
				return processor;
			}
		}

		public event EventHandler<BXBlogCutTagEventArgs> RenderBeginCut
		{
			add
			{
				Processor.RenderBeginCut += value;
			}
			remove
			{
				Processor.RenderBeginCut -= value;
			}
		}
		public event EventHandler<BXBlogCutTagEventArgs> RenderEndCut
		{
			add
			{
				Processor.RenderEndCut += value;
			}
			remove
			{
				Processor.RenderEndCut -= value;
			}
		}

		public void Delete()
		{
			if (fatalError != ErrorCode.None)
				return;

			BXPrincipal user = BXPrincipal.Current;
			int userId = BXIdentity.Current.Id;

			if (auth.CanDeleteThisPost)
			{
				post.Delete();
				RedirectTemplateUrl(BlogUrlTemplate, replace);
				return;
			}

			Fatal(ErrorCode.UnauthorizedDeletePost);
		}
        public string GetErrorHtml(ErrorCode code)
		{
			switch (code)
			{
				case ErrorCode.FatalException:
					return BXPrincipal.Current.IsCanOperate(BXRoleOperation.Operations.SystemMaintenance) ? ("<pre>" + Encode(fatalException.ToString()) + "</pre>") : GetMessage("Error.Unknown");
				case ErrorCode.FatalPostNotFound:
					return GetMessage("Error.PostNotFound");
				case ErrorCode.UnauthorizedViewPost:
					return GetMessage("Error.UnauthorizedView");
				case ErrorCode.UnauthorizedDeletePost:
					return GetMessage("Error.UnauthorizedDelete");
				default:
					return GetMessage("Error.Unknown");
			}
		}

		private BXParamsBag<object> GetReplaceParameters()
		{
			BXParamsBag<object> replace = new BXParamsBag<object>();
			replace["BlogId"] = blog.Id;
			replace["BlogSlug"] = blog.Slug;
			replace["PostId"] = post.Id;
			DateTime date = post.DatePublished;
			replace["PostYear"] = date.Year;
			replace["PostMonth"] = date.Month;
			replace["PostDay"] = date.Day;
			replace["UserId"] = post.AuthorId;
			return replace;
		}
		private void Fatal(ErrorCode code)
		{
			if (code == ErrorCode.FatalException)
				throw new InvalidOperationException("Use method with Exception argument");
			fatalError = code;
			if (!templateIncluded)
			{
				templateIncluded = true;
				IncludeComponentTemplate();
			}
		}
		private void Fatal(Exception ex)
		{
			if (ex == null)
				throw new ArgumentNullException("ex");

			fatalError = ErrorCode.FatalException;
			fatalException = ex;
			if (!templateIncluded)
			{
				templateIncluded = true;
				IncludeComponentTemplate();
			}
		}
		
		protected void Page_Load(object sender, EventArgs e)
		{
			fatalError = ErrorCode.None;
			try
			{
				if (PostId < 0)
				{
					Fatal(ErrorCode.FatalPostNotFound);
					return;
				}

				BXBlogPostCollection posts = BXBlogPost.GetList(
					new BXFilter(
						new BXFilterItem(BXBlogPost.Fields.Id, BXSqlFilterOperators.Equal, PostId),
						new BXFilterItem(BXBlogPost.Fields.Blog.Categories.Category.Sites.SiteId, BXSqlFilterOperators.Equal, DesignerSite)
					),
					null,
					new BXSelectAdd(BXBlogPost.Fields.Blog, BXBlogPost.Fields.Author, BXBlogPost.Fields.Author.User, BXBlogPost.Fields.Author.User.Image),
					null
				);

				if (posts.Count > 0)
					post = posts[0];

				if (post == null)
				{
					Fatal(ErrorCode.FatalPostNotFound);
					return;
				}

				blog = post.Blog;
				if (blog == null || !string.IsNullOrEmpty(BlogSlug) && blog.Slug != BlogSlug)
				{
					Fatal(ErrorCode.FatalPostNotFound);
					return;
				}

				auth = new BXBlogAuthorization(blog, post);

				if (!auth.CanReadThisPost)
				{
					Fatal(ErrorCode.UnauthorizedViewPost);
					return;
				}

				string title = post.TextEncoder.Decode(post.Title);
				replace = GetReplaceParameters();
				postInfo = new PostInfo();
				postInfo.Post = post;
				postInfo.AuthorNameHtml = BXWordBreakingProcessor.Break(post.TextEncoder.Decode(post.AuthorName), MaxWordLength, true);
				postInfo.TitleHtml = BXWordBreakingProcessor.Break(title, MaxWordLength, true);
				postInfo.processor = Processor;
				postInfo.PostViewHref = Encode(ResolveTemplateUrl(PostViewUrlTemplate, replace));
				postInfo.PostEditHref = Encode(ResolveTemplateUrl(PostEditUrlTemplate, replace));
				postInfo.UserProfileHref = Encode(ResolveTemplateUrl(UserProfileUrlTemplate, replace));
				postInfo.BlogHref = Encode(ResolveTemplateUrl(BlogUrlTemplate, replace));

				//Set page title
				BXPublicPage bitrixPage = Page as BXPublicPage;
				if (bitrixPage != null && !IsComponentDesignMode)
				{
					if (Parameters.GetBool("SetPageTitle", true))
					{
						if (!string.IsNullOrEmpty(title))
						{
							bitrixPage.MasterTitleHtml = postInfo.TitleHtml;
							bitrixPage.Title = Encode(title);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Fatal(ex);
				return;
			}
			if (!templateIncluded)
			{
				templateIncluded = true;
				IncludeComponentTemplate();
			}
		}
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);

			foreach (string param in new string[] { Parameters.GetString("ThemeCssFilePath"), Parameters.GetString("ColorCssFilePath") })
			{
				if (BXStringUtility.IsNullOrTrimEmpty(param))
					continue;

				string path = param;
				try
				{
					path = BXPath.ToVirtualRelativePath(path);
					if (BXSecureIO.FileExists(path))
						BXPage.RegisterStyle(path);
				}
				catch
				{
				}
			}
			int userId = BXIdentity.Current.Id;
			if (fatalError == ErrorCode.None && (userId == 0 || userId != post.AuthorId))
			{
				post.ViewCount++;
				post.Save();
			}
		}
		protected override void PreLoadComponentDefinition()
		{
			Title = GetMessageRaw("Title");
			Description = GetMessageRaw("Description");
			Icon = "images/icon.gif";
			Group = BXBlogModuleConfiguration.GetComponentGroup();

			BXCategory mainCategory = BXCategory.Main;
			BXCategory urlCategory = BXCategory.UrlSettings;
			BXCategory additionalSettingsCategory = BXCategory.AdditionalSettings;

			ParamsDefinition.Add("ThemeCssFilePath", new BXParamText(GetMessageRaw("Param.ThemeCssFilePath"), "~/bitrix/components/bitrix/blog/templates/.default/style.css", mainCategory));
			ParamsDefinition.Add("ColorCssFilePath", new BXParamText(GetMessageRaw("Param.ColorCssFilePath"), "~/bitrix/components/bitrix/blog/templates/.default/themes/default/style.css", mainCategory));

			ParamsDefinition.Add("BlogSlug", new BXParamText(GetMessageRaw("Param.BlogSlug"), "", mainCategory));
			ParamsDefinition.Add("PostId", new BXParamText(GetMessageRaw("Param.PostId"), "", mainCategory));

			ParamsDefinition.Add("MaxWordLength", new BXParamText(GetMessageRaw("Param.MaxWordLength"), "15", additionalSettingsCategory));
			ParamsDefinition.Add("SetPageTitle", new BXParamYesNo(GetMessageRaw("Param.SetPageTitle"), true, additionalSettingsCategory));

			ParamsDefinition.Add("BlogUrlTemplate", new BXParamText(GetMessageRaw("Param.BlogUrlTemplate"), "Blog.aspx?blog=#BlogSlug#", urlCategory));
			ParamsDefinition.Add("UserProfileUrlTemplate", new BXParamText(GetMessageRaw("Param.UserProfileUrlTemplate"), "User.aspx?user=#UserId#", urlCategory));
			ParamsDefinition.Add("PostViewUrlTemplate", new BXParamText(GetMessageRaw("Param.PostViewUrlTemplate"), "Post.aspx?post=#PostId#", urlCategory));
			ParamsDefinition.Add("PostEditUrlTemplate", new BXParamText(GetMessageRaw("Param.PostEditUrlTemplate"), "PostEdit.aspx?post=#PostId#", urlCategory));
		}

		public enum ErrorCode
		{
			None = 0,
			Fatal = 1,
			Unauthorized = 2,
			FatalComponentNotExecuted = Fatal | (0 << 2),
			FatalException = Fatal | (1 << 2),
			FatalPostNotFound = Fatal | (2 << 2),
			UnauthorizedViewPost = Unauthorized | (0 << 2),
			UnauthorizedDeletePost = Unauthorized | (1 << 2)
		}
		public class PostInfo
		{
			internal BXBlogPostChain processor;
			private string authorNameHtml;
			private string titleHtml;
			private string postEditHref;
			private string userProfileHref;
			private string blogHref;
			private string postViewHref;
			private BXBlogPost post;

			public BXBlogPost Post
			{
				get
				{
					return post;
				}
				internal set
				{
					post = value;
				}
			}
			public string AuthorNameHtml
			{
				get
				{
					return authorNameHtml;
				}
				internal set
				{
					authorNameHtml = value;
				}
			}
			public string TitleHtml
			{
				get
				{
					return titleHtml;
				}
				internal set
				{
					titleHtml = value;
				}
			}
			public string PostEditHref
			{
				get
				{
					return postEditHref;
				}
				internal set
				{
					postEditHref = value;
				}
			}
			public string UserProfileHref
			{
				get
				{
					return userProfileHref;
				}
				internal set
				{
					userProfileHref = value;
				}
			}
			public string BlogHref
			{
				get
				{
					return blogHref;
				}
				internal set
				{
					blogHref = value;
				}
			}
			public string PostViewHref
			{
				get
				{
					return postViewHref;
				}
				internal set
				{
					postViewHref = value;
				}
			}

			internal PostInfo()
			{

			}
			
			public void RenderPostContent(HtmlTextWriter writer)
			{
				processor.Process(post.Content, writer);
			}
			public string GetPostContent()
			{
				return processor.Process(post.Content);
			}
		}
	}

	public class BlogPostTemplate : BXComponentTemplate<BlogPostComponent>
	{
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			if ((Component.FatalError & BlogPostComponent.ErrorCode.Fatal) != 0)
				BXError404Manager.Set404Status(Response);
		}
		protected override void Render(HtmlTextWriter writer)
		{
			StartWidth = "100%";
			base.Render(writer);
		}
	}
}

