/// <summary>
 ///     Returns false for <see cref="News" /> posts and comment threads on <see cref="Clan" />s, <see cref="Mission" />s,
 ///     PlanetWars <see cref="Planet" />s and <see cref="SpringBattle" />s; true otherwise
 /// </summary>
 /// <param name="thread"></param>
 /// <returns></returns>
 bool IsNormalThread(ForumThread thread) {
     if (thread.Clans != null && thread.Clans.Count > 0) return false;
     if (thread.Missions != null && thread.Missions.Count > 0) return false;
     if (thread.Planets != null && thread.Planets.Count > 0) return false;
     if (thread.SpringBattles != null && thread.SpringBattles.Count > 0) return false;
     if (thread.News != null && thread.News.Count > 0) return false;
     return true;
 }
		public ActionResult PostNews(News nn, HttpPostedFileBase image)
		{
			if (string.IsNullOrEmpty(nn.Title) || string.IsNullOrEmpty(nn.Text)) return Content("Empty text!");

			var db = new ZkDataContext();
			using (var scope = new TransactionScope())
			{
			    News news;
                if (nn.NewsID == 0)
                {
                    news = new News();
                    news.Created = nn.Created;
                }
                else news = db.News.Single(x => x.NewsID == nn.NewsID);
		        news.AuthorAccountID = Global.AccountID;
                news.Title=  nn.Title;
                news.Text = nn.Text;

				Image im = null;
				if (image != null && image.ContentLength > 0)
				{
					im = Image.FromStream(image.InputStream);
					news.ImageExtension = Path.GetExtension(image.FileName);
					news.ImageContentType = image.ContentType;
					news.ImageLength = image.ContentLength;
				}

                news.HeadlineUntil = nn.HeadlineUntil;
                string postText = news.Text;

                if (nn.NewsID == 0)
                {
                    var thread = new ForumThread()
                                 {
                                     Created = news.Created,
                                     CreatedAccountID = news.AuthorAccountID,
                                     Title = news.Title,
                                     ForumCategoryID = db.ForumCategories.Single(x => x.IsNews).ForumCategoryID
                                 };

                    
                    thread.ForumPosts.Add(new ForumPost() { Created = news.Created, Text = postText, AuthorAccountID = news.AuthorAccountID });
                    db.ForumThreads.InsertOnSubmit(thread);
                    db.SubmitChanges();
                    news.ForumThreadID = thread.ForumThreadID;
                    db.News.InsertOnSubmit(news);
                }
			    db.SubmitChanges();

                // add image to the start of the forum post we made
                // do it down here so it gets the correct news ID
                if (!String.IsNullOrWhiteSpace(news.ImageRelativeUrl) && news.ForumThread != null)
                {
                    postText = "[img]" + news.ImageRelativeUrl + "[/img]" + Environment.NewLine + postText;
                    news.ForumThread.ForumPosts.ElementAt(0).Text = postText;
                    db.SubmitChanges();
                }

				if (im != null)
				{
					im.Save(Server.MapPath(news.ImageRelativeUrl));
                    Image thumb = im.GetResized(120, (int)Math.Round(120.0 / im.Width * im.Height), InterpolationMode.HighQualityBicubic);
                    thumb.Save(Server.MapPath(news.ThumbRelativeUrl));
				}
				scope.Complete();
			}
			return Content("Posted!");
		}
        public static MvcHtmlString Print(this HtmlHelper helper, ForumThread thread) {
            var url = Global.UrlHelper();

            ForumThreadLastRead lastRead = null;
            ForumLastRead lastReadForum = null;
            DateTime? lastTime = null;
            if (Global.Account != null)
            {
                lastRead = Global.Account.ForumThreadLastReads.FirstOrDefault(x => x.ForumThreadID == thread.ForumThreadID);
                lastReadForum = Global.Account.ForumLastReads.FirstOrDefault(x => x.ForumCategoryID == thread.ForumCategoryID);
                if (lastReadForum != null) lastTime = lastReadForum.LastRead;
            }
            if (lastRead != null && (lastTime == null || lastRead.LastRead > lastTime)) lastTime = lastRead.LastRead;
            ForumPost post = null;
            if (lastTime != null) post = thread.ForumPosts.FirstOrDefault(x => x.Created > lastTime);
            int page = post != null ? ZeroKWeb.Controllers.ForumController.GetPostPage(post) : (thread.PostCount-1)/GlobalConst.ForumPostsPerPage;

            string link;
            if (page > 0) link = url.Action("Thread", "Forum", new { id = thread.ForumThreadID, page = page});
            else link = url.Action("Thread", "Forum", new { id = thread.ForumThreadID });
            link = string.Format("<a href='{0}' title='$thread${1}'>", link, thread.ForumThreadID);

            string format;

            if (lastTime == null) format = "<span>{0}<img src='/img/mail/mail-unread.png' height='15' /><i>{1}</i></a></span>";
            else {
                if (lastTime >= thread.LastPost) format = "<span>{0}<img src='/img/mail/mail-read.png' height='15' />{1}</a></span>";
                else {
                    if (lastRead != null && lastRead.LastPosted != null) format = "<span>{0}<img src='/img/mail/mail-new.png' height='15' /><b>{1}</b></a></span>";
                    else format = "<span>{0}<img src='/img/mail/mail-unread.png' height='15' />{1}</a></span>";
                }
            }

            return new MvcHtmlString(string.Format(format, link, HttpUtility.HtmlEncode(thread.Title)));
        }
        public ActionResult SubmitPost(
            int? threadID,
            int? categoryID,
            int? resourceID,
            int? missionID,
            int? springBattleID,
            int? clanID,
            int? planetID,
            string text,
            string title,
            string wikiKey,
            int? forumPostID) {
            if (threadID == null && missionID == null && resourceID == null && springBattleID == null && clanID == null && planetID == null &&
                forumPostID == null && string.IsNullOrWhiteSpace(title)) return Content("Cannot post new thread with blank title");
            if (string.IsNullOrWhiteSpace(text)) return Content("Please type some text :)");

            var penalty = Punishment.GetActivePunishment(Global.AccountID, Request.ServerVariables["REMOTE_ADDR"], 0, x => x.BanForum);
            if (penalty != null)
            {
                return
                    Content(
                        string.Format("You cannot post while banned from forum!\nExpires: {0} UTC\nReason: {1}", penalty.BanExpires, penalty.Reason));
            }

            var db = new ZkDataContext();
            using (var scope = new TransactionScope())
            {
                var thread = db.ForumThreads.SingleOrDefault(x => x.ForumThreadID == threadID);
                var category = thread?.ForumCategory;
                if (category == null && categoryID != null) category = db.ForumCategories.FirstOrDefault(x => x.ForumCategoryID == categoryID);
                string currentTitle = null;

                // update title
                if (thread != null && !string.IsNullOrEmpty(title))
                {
                    currentTitle = thread.Title;
                    thread.Title = title;
                    thread.WikiKey = wikiKey;
                }
                if (thread != null && planetID != null)
                {
                    var planet = db.Planets.Single(x => x.PlanetID == planetID);
                    thread.Title = "Planet " + planet.Name;
                }
                if (thread != null && clanID != null)
                {
                    var clan = db.Clans.Single(x => x.ClanID == clanID);
                    thread.Title = "Clan " + clan.ClanName;
                }
                if (thread != null && missionID != null)
                {
                    var mission = db.Missions.Single(x => x.MissionID == missionID);
                    thread.Title = "Mission " + mission.Name;
                }
                if (thread != null && resourceID != null)
                {
                    var map = db.Resources.Single(x => x.ResourceID == resourceID);
                    thread.Title = "Map " + map.InternalName;
                }

                if (threadID == null && category != null) // new thread
                {
                    if (category.IsLocked) return Content("Thread is locked");

                    if (category.ForumMode == ForumMode.Wiki)
                    {
                        if (string.IsNullOrEmpty(wikiKey) || !Account.IsValidLobbyName(wikiKey))
                        {
                            return Content("You need to set a valid wiki key");
                        }
                        if (db.ForumThreads.Any(y => y.WikiKey == wikiKey))
                        {
                            return Content("This wiki key already exists");
                        }
                    }

                    if (string.IsNullOrEmpty(title)) return Content("Title cannot be empty");
                    thread = new ForumThread();
                    thread.CreatedAccountID = Global.AccountID;
                    thread.Title = title;
                    thread.WikiKey = wikiKey;
                    thread.ForumCategoryID = category.ForumCategoryID;
                    db.ForumThreads.InsertOnSubmit(thread);
                }

                if (thread == null && resourceID != null) // non existing thread, we posted new post on map
                {
                    var res = db.Resources.Single(x => x.ResourceID == resourceID);
                    if (res.ForumThread != null) return Content("Double post");
                    thread = new ForumThread
                    {
                        Title = "Map " + res.InternalName,
                        CreatedAccountID = Global.AccountID,
                        LastPostAccountID = Global.AccountID
                    };
                    thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.ForumMode == ForumMode.Maps);
                    res.ForumThread = thread;
                    db.ForumThreads.InsertOnSubmit(thread);
                }

                if (thread == null && springBattleID != null) // non existing thread, we posted new post on battle
                {
                    var bat = db.SpringBattles.Single(x => x.SpringBattleID == springBattleID);
                    if (bat.ForumThread != null) return Content("Double post");
                    thread = new ForumThread { Title = bat.FullTitle, CreatedAccountID = Global.AccountID, LastPostAccountID = Global.AccountID };
                    thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.ForumMode == ForumMode.SpringBattles);
                    bat.ForumThread = thread;
                    db.ForumThreads.InsertOnSubmit(thread);
                }

                if (thread == null && clanID != null)
                {
                    var clan = db.Clans.Single(x => x.ClanID == clanID);
                    if (clan.ForumThread != null) return Content("Double post");
                    thread = new ForumThread
                    {
                        Title = "Clan " + clan.ClanName,
                        CreatedAccountID = Global.AccountID,
                        LastPostAccountID = Global.AccountID
                    };
                    thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.ForumMode == ForumMode.Clans);
                    clan.ForumThread = thread;
                    thread.Clan = clan;
                    db.ForumThreads.InsertOnSubmit(thread);
                }

                if (thread == null && planetID != null)
                {
                    var planet = db.Planets.Single(x => x.PlanetID == planetID);
                    if (planet.ForumThread != null) return Content("Double post");
                    thread = new ForumThread
                    {
                        Title = "Planet " + planet.Name,
                        CreatedAccountID = Global.AccountID,
                        LastPostAccountID = Global.AccountID
                    };
                    thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.ForumMode == ForumMode.Planets);
                    planet.ForumThread = thread;
                    db.ForumThreads.InsertOnSubmit(thread);
                }


                if (thread == null) return Content("Thread not found");
                if (thread.IsLocked) return Content("Thread is locked");

                var lastPost = thread.ForumPosts.OrderByDescending(x => x.ForumPostID).FirstOrDefault();

                int? gotoPostId = null;
                //double post preventer
                if (lastPost == null || lastPost.AuthorAccountID != Global.AccountID || lastPost.Text != text ||
                    (!string.IsNullOrEmpty(title) && title != currentTitle))
                {
                    if (forumPostID != null)
                    {
                        var post = thread.ForumPosts.Single(x => x.ForumPostID == forumPostID);
                        if (!post.CanEdit(Global.Account)) throw new ApplicationException("Not authorized to edit the post");
                        post.ForumPostEdits.Add(
                            new ForumPostEdit
                            {
                                EditorAccountID = Global.AccountID,
                                EditTime = DateTime.UtcNow,
                                OriginalText = post.Text,
                                NewText = text
                            });
                        post.Text = text;
                    } else
                    {
                        var p = new ForumPost { AuthorAccountID = Global.AccountID, Text = text, Created = DateTime.UtcNow };
                        thread.ForumPosts.Add(p);
                        db.SaveChanges();
                        gotoPostId = p.ForumPostID;
                    }

                    thread.LastPost = DateTime.UtcNow;
                    thread.LastPostAccountID = Global.AccountID;
                    thread.PostCount = thread.ForumPosts.Count();
                    thread.UpdateLastRead(Global.AccountID, true, thread.LastPost);

                    db.SaveChanges();
                }
                
                scope.Complete();

                
                if (missionID.HasValue) return RedirectToAction("Detail", "Missions", new { id = missionID });
                if (resourceID.HasValue) return RedirectToAction("Detail", "Maps", new { id = resourceID });
                if (springBattleID.HasValue) return RedirectToAction("Detail", "Battles", new { id = springBattleID });
                if (clanID.HasValue) return RedirectToAction("Detail", "Clans", new { id = clanID });
                if (planetID.HasValue) return RedirectToAction("Planet", "Planetwars", new { id = planetID });
                if (forumPostID.HasValue) return RedirectToAction("Thread","Forum", new { id = thread.ForumThreadID, postID = forumPostID });
                return RedirectToAction("Thread", "Forum", new { id = thread.ForumThreadID, postID = gotoPostId });
            }
        }
 partial void DeleteForumThread(ForumThread instance);
 partial void UpdateForumThread(ForumThread instance);
 partial void InsertForumThread(ForumThread instance);
		public ActionResult SubmitPost(int? threadID, int? categoryID, int? resourceID, int? missionID, int? springBattleID, int? clanID, int? planetID, string text, string title, int? forumPostID)
		{
            if (threadID == null && missionID == null && resourceID == null && springBattleID == null && clanID ==null && planetID == null && forumPostID==null && string.IsNullOrWhiteSpace(title)) return Content("Cannot post new thread with blank title");
			if (string.IsNullOrWhiteSpace(text)) return Content("Please type some text :)");

            var penalty = ZkData.Punishment.GetActivePunishment(Global.AccountID, "", 0, x => x.BanForum);
            if (penalty != null)
            {
                return Content(string.Format("You cannot post while banned from forum!\nExpires: {0} UTC\nReason: {1}", penalty.BanExpires, penalty.Reason));
            }

			var db = new ZkDataContext();
			using (var scope = new TransactionScope())
			{
				var thread = db.ForumThreads.SingleOrDefault(x => x.ForumThreadID == threadID);

				// update title
                if (thread != null && !String.IsNullOrEmpty(title)) thread.Title = title;
				if (thread != null && planetID != null)
				{
					var planet = db.Planets.Single(x => x.PlanetID == planetID);
					thread.Title = "Planet "  + planet.Name;
				}
				if (thread != null && clanID != null)
				{
					var clan = db.Clans.Single(x => x.ClanID == clanID);
					thread.Title = "Clan " + clan.ClanName;
				}
				if (thread != null && missionID != null)
				{
					var mission = db.Missions.Single(x => x.MissionID == missionID);
					thread.Title = "Mission " +mission.Name;
				}
                if (thread != null && resourceID != null) {
                    var map = db.Resources.Single(x => x.ResourceID == resourceID);
                    thread.Title = "Map " + map.InternalName;
                }


			    if (threadID == null && categoryID.HasValue) // new thread
				{
					var cat = db.ForumCategories.Single(x => x.ForumCategoryID == categoryID.Value);
					if (cat.IsLocked) return Content("Thread is locked");

					if (string.IsNullOrEmpty(title)) return Content("Title cannot be empty");
					thread = new ForumThread();
					thread.CreatedAccountID = Global.AccountID;
					thread.Title = title;
					thread.ForumCategoryID = cat.ForumCategoryID;
					db.ForumThreads.InsertOnSubmit(thread);
				}

				if (thread == null && resourceID != null) // non existing thread, we posted new post on map
				{
					var res = db.Resources.Single(x => x.ResourceID == resourceID);
                    if (res.ForumThread != null) return Content("Double post");
                    thread = new ForumThread() { Title = "Map " +res.InternalName, CreatedAccountID = Global.AccountID, LastPostAccountID = Global.AccountID };
					thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.IsMaps);
					res.ForumThread = thread;
					db.ForumThreads.InsertOnSubmit(thread);
				}

				if (thread == null && springBattleID != null) // non existing thread, we posted new post on battle
				{
					var bat = db.SpringBattles.Single(x => x.SpringBattleID == springBattleID);
                    if (bat.ForumThread != null) return Content("Double post");
                    thread = new ForumThread() { Title =  bat.FullTitle, CreatedAccountID = Global.AccountID, LastPostAccountID = Global.AccountID };
					thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.IsSpringBattles);
				    bat.ForumThread = thread;
					db.ForumThreads.InsertOnSubmit(thread);
				}

				if (thread == null && clanID != null)
				{
					var clan = db.Clans.Single(x => x.ClanID == clanID);
                    if (clan.ForumThread != null) return Content("Double post");
                    thread = new ForumThread() { Title = "Clan " +clan.ClanName, CreatedAccountID = Global.AccountID, LastPostAccountID = Global.AccountID };
					thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.IsClans);
					clan.ForumThread = thread;
					thread.Clan = clan;
					db.ForumThreads.InsertOnSubmit(thread);
				}

				if (thread == null && planetID != null)
				{
					var planet = db.Planets.Single(x => x.PlanetID == planetID);
                    if (planet.ForumThread != null) return Content("Double post");
                    thread = new ForumThread() { Title = "Planet " +planet.Name, CreatedAccountID = Global.AccountID, LastPostAccountID = Global.AccountID };
					thread.ForumCategory = db.ForumCategories.FirstOrDefault(x => x.IsPlanets);
					planet.ForumThread = thread;
					db.ForumThreads.InsertOnSubmit(thread);
				}

				if (thread == null) return Content("Thread not found");
				if (thread.IsLocked) return Content("Thread is locked");
                
				var lastPost = thread.ForumPosts.OrderByDescending(x => x.ForumPostID).FirstOrDefault();

                //double post preventer
                if (lastPost == null || lastPost.AuthorAccountID != Global.AccountID || lastPost.Text != text)
				{
                    if (forumPostID != null) {
                        var post = thread.ForumPosts.Single(x => x.ForumPostID == forumPostID);
                        if (post.AuthorAccountID != Global.AccountID && !Global.Account.IsZeroKAdmin) throw new ApplicationException("Not authorized to edit the post");
                        post.ForumPostEdits.Add(new ForumPostEdit() { 
                                EditorAccountID = Global.AccountID,
                                EditTime = DateTime.UtcNow,
                                OriginalText = post.Text,
                                NewText = text
                        });
                        post.Text = text;


                    } else thread.ForumPosts.Add(new ForumPost() { AuthorAccountID = Global.AccountID, Text = text, Created = DateTime.UtcNow});

					
                    thread.LastPost = DateTime.UtcNow;
					thread.LastPostAccountID = Global.AccountID;
					thread.PostCount = thread.ForumPosts.Count();
					thread.UpdateLastRead(Global.AccountID, true, thread.LastPost);

					db.SubmitChanges();
				}
                int lastPage = ((thread.PostCount - 1) / PageSize);
                scope.Complete();

				if (missionID.HasValue) return RedirectToAction("Detail", "Missions", new { id = missionID });
				else if (resourceID.HasValue) return RedirectToAction("Detail", "Maps", new { id = resourceID });
				else if (springBattleID.HasValue) return RedirectToAction("Detail", "Battles", new { id = springBattleID });
				else if (clanID.HasValue) return RedirectToAction("Detail", "Clans", new { id = clanID });
				else if (planetID.HasValue) return RedirectToAction("Planet", "Planetwars", new { id = planetID });
                else if (forumPostID.HasValue) return RedirectToAction("Thread", new { id = thread.ForumThreadID, postID = forumPostID });
                else return RedirectToAction("Thread", new { id = thread.ForumThreadID, page = lastPage});
			}
		}