using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using TABS.MailCarrier.WebSDK;
using TABS.MailCarrier.WebSDK.Board;
using TABS.MailCarrier.WebSDK.User;

/// <summary>
/// New.aspx 파라미터 
///   action (필수) - new, reply, modify
///   board (필수, GUID) - 게시판 ID
///   article (선택, int) - reply/modify에서 게시글 ID
///   page (선택, int) - 페이지 번호(0에서 시작)
///   searchCategoty (선택) - 검색 카테고리(subject, author, content)
///   searchKeyword (선택) - 검색 키워드 
/// </summary>
public partial class Board_NewTM : System.Web.UI.Page
{
    [Serializable]
    public class AttachmentEx : Attachment
    {
        public bool NewAttach { get; set; }
        public bool Deleted { get; set; }

        /// <summary>
        /// 새 첨부 파일 추가
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="filePath"></param>
        public AttachmentEx(string fileName, string filePath) : base(fileName, filePath)
        {
            NewAttach = true;
            Deleted = false;
        }

        /// <summary>
        /// 편집 모드로 파일 로딩
        /// </summary>
        /// <param name="fileId"></param>
        public AttachmentEx(Guid fileId) : base(fileId)
        {
            NewAttach = false;
            Deleted = false;
        }
    }

    [Serializable]
    public class AttachmentExCollection : List<AttachmentEx>
    {
    }

    protected string _action;
    protected Guid _boardId;
    protected int _articleId;
    protected string _page;
    protected string _searchCategoty;
    protected string _searchKeyword;
    protected string _listPageParams1;
    protected string _listPageParams2;

    private AttachmentExCollection _attachments = null;   // 첨부 파일 목록: ViewState에 저장

    protected override void InitializeCulture()
    {
        string defLang = WebUser.CurrentUser.UiLanguage;
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(defLang);
        Thread.CurrentThread.CurrentUICulture = new CultureInfo(defLang);
        base.InitializeCulture();
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        WebUtil.SetKendoUiLocalResource(Page.Header, WebUser.CurrentUser.UiLanguage);
        WebUtil.SetMcCommonCss(Page.Header);
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        _action = WebParam.GetStrParamValue("action");
        _boardId = WebParam.GetGuidParamValue("board");
        _articleId = WebParam.GetIntParamValue("article");
        _page = WebParam.GetStrParamValue("page");
        _searchCategoty = WebParam.GetStrParamValue("searchCategoty");
        _searchKeyword = WebParam.GetStrParamValue("searchKeyword");
        _listPageParams1 = string.Format("board={0}", _boardId);
        _listPageParams2 = string.Format("board={0}&page={1}&searchCategoty={2}&searchKeyword={3}", _boardId, _page, _searchCategoty, Server.UrlEncode(_searchKeyword));

        if (!IsPostBack)
        {
            Page.Title = AppSetting.GetTitleInfo(Request).Title;
            _attachments = new AttachmentExCollection();

            Board.RsAccessFlag accessFlag = Board.GetAccessFlag(WebUser.CurrentUser.DomainUserID, _boardId);
            if ((accessFlag & (Board.RsAccessFlag.Write | Board.RsAccessFlag.Admin)) <= 0 || !AppSetting.PassDisplayBoardFilter(_boardId, WebUser.CurrentUser.MailAddress))
            {
                // 게시판에 글을 게시할 권한이 없습니다.
                Response.Redirect("~/Error.aspx?code=15", true);
                return;
            }
            if (CheckPermitSize(_boardId))
            {
                // 지정된 게시판의 용량이 초과하여 더이상 글을 쓸 수 없습니다.
                Response.Redirect("~/Error.aspx?code=16", true);
                return;
            }

            if (_action == "new")
            {
                InitNewArticle();
            }
            else if (_action == "reply")
            {
                InitReplyArticle();                
                BootstrapUtil.CollapseControl(fixedTopPanel, true);
            }
            else if (_action == "modify")
            {
                Article article = new Article(_articleId);
                article.Load();
                // 글 작성자 본인(쓰기 권한 필요) 및 관리자만 글을 수정할 수 있다.
                if (!(article.AuthorID == WebUser.CurrentUser.UserAccount || (accessFlag & Board.RsAccessFlag.Admin) > 0))
                {
                    Response.Redirect("~/Error.aspx?code=18", true);
                    return;
                }
                bool parentArticle = (article.Depth == 0);
                LoadModifyArticle(article);
                FixedTopCheckBox.Checked = (article.Flag & Article.AttrFlag.FixedTop) > 0;
                BootstrapUtil.CollapseControl(fixedTopPanel, !parentArticle);
            }
            if ((accessFlag & Board.RsAccessFlag.Admin) == 0)
            {
                BootstrapUtil.CollapseControl(fixedTopPanel, true);
            }

            ViewState["_attachments"] = _attachments;
        }
        else
        {
            _attachments = (AttachmentExCollection)ViewState["_attachments"];
        }
    }

    #region ASP.NET Event Handlers

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        // 글 저장/수정 시에도 권한 검사를 진행한다.
        Board.RsAccessFlag accessFlag = Board.RsAccessFlag.None;
        string boardArticle = WebUtil.GetFullHtmlWithContainer(HttpUtility.HtmlDecode(MsgTextBox.Value));
        if (_action == "new")
        {
            accessFlag = Board.GetAccessFlag(WebUser.CurrentUser.DomainUserID, _boardId);
            if ((accessFlag & (Board.RsAccessFlag.Write | Board.RsAccessFlag.Admin)) <= 0)
            {
                // 게시판에 글을 게시할 권한이 없습니다.
                Response.Redirect("~/Error.aspx?code=15", true);
                return;
            }
            Board board = new Board(_boardId);
            Article article = new Article();
            article.AuthorID = WebUser.CurrentUser.UserAccount;
            article.AuthorName = AuthorTextBox.Value;
            article.Subject = SubjectTextBox.Value;
            List<Attachment> attachments = GetAttachments();
            article.Body = GetBodyHTML(boardArticle, attachments);
            if (FixedTopCheckBox.Checked) article.Flag = Article.AttrFlag.FixedTop;

            board.WebsiteAppUrl = WebParam.GetCurrentWebAppUrl();
            board.WebsiteAppUrl1 = AppSetting.GetTitleInfo(Request)["website1"];
            board.AddArticle(article, attachments.ToArray(), AppSetting.NewArticleNotificationTemplateFile);
            WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Board/NewTM.aspx", "Add", string.Format("BID:{0}, AID:{1}, S:{2}", _boardId.ToString(), article.ID, article.Subject));
            Response.Redirect("List.aspx?" + _listPageParams1);
        }
        else if (_action == "reply")
        {
            Article dummyArticle = new Article(_articleId);
            dummyArticle.Load();
            accessFlag = Board.GetAccessFlag(WebUser.CurrentUser.DomainUserID, dummyArticle.BoardID);
            if ((accessFlag & (Board.RsAccessFlag.Write | Board.RsAccessFlag.Admin)) <= 0)
            {
                // 게시판에 글을 게시할 권한이 없습니다.
                Response.Redirect("~/Error.aspx?code=15", true);
                return;
            }
            Board board = new Board(_boardId);
            Article article = new Article();
            article.AuthorID = WebUser.CurrentUser.UserAccount;
            article.AuthorName = AuthorTextBox.Value;
            article.Subject = SubjectTextBox.Value;
            List<Attachment> attachments = GetAttachments();
            article.Body = GetBodyHTML(boardArticle, attachments);

            board.WebsiteAppUrl = WebParam.GetCurrentWebAppUrl();
            board.WebsiteAppUrl1 = AppSetting.GetTitleInfo(Request)["website1"];
            board.AddReplyArticle(_articleId, article, attachments.ToArray(), AppSetting.NewArticleNotificationTemplateFile);
            WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Board/NewTM.aspx", "Reply", string.Format("BID:{0}, AID:{1}, S:{2}", _boardId.ToString(), article.ID, article.Subject));
            Response.Redirect("List.aspx?" + _listPageParams2);
        }
        else if (_action == "modify")
        {
            Article dummyArticle = new Article(_articleId);
            dummyArticle.Load();
            accessFlag = Board.GetAccessFlag(WebUser.CurrentUser.DomainUserID, dummyArticle.BoardID);
            // 글 작성자 본인(쓰기 권한 필요) 및 관리자만 글을 수정할 수 있다.
            if (!(((accessFlag & Board.RsAccessFlag.Write) > 0 && dummyArticle.AuthorID == WebUser.CurrentUser.UserAccount) || (accessFlag & Board.RsAccessFlag.Admin) > 0))
            {
                // 게시판에 글을 게시할 권한이 없습니다.
                Response.Redirect("~/Error.aspx?code=15", true);
                return;
            }
            Article article = new Article(_articleId);
            article.AuthorName = AuthorTextBox.Value;
            article.Subject = SubjectTextBox.Value;
            List<Attachment> added, removed;
            GetAddedRemovedAttachments(out added, out removed);
            article.Body = GetBodyHTML(boardArticle, added);
            if (FixedTopCheckBox.Checked) article.Flag = Article.AttrFlag.FixedTop;
            
            article.Update(added.ToArray(), removed.ToArray());
            WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Board/NewTM.aspx", "Modify", string.Format("BID:{0}, AID:{1}, S:{2}", dummyArticle.BoardID.ToString(), article.ID, article.Subject));
            Response.Redirect("List.aspx?" + _listPageParams2);
        }
    }

    protected void AddAttachFileButton_Click(object sender, EventArgs e)
    {
        // 업로드된 파일 정보는 JsonUploadFilesHidden 변수에 JSON 문자열로 전달
        JavaScriptSerializer json = new JavaScriptSerializer();
        List<JsonUploadFile> jsonRecipientList = json.Deserialize<List<JsonUploadFile>>(JsonUploadFilesHidden.Value);

        ExtIconMap iconMap = new ExtIconMap();
        long currentSize = GetCurrentTotalAttachSize();
        foreach (JsonUploadFile upfile in jsonRecipientList)
        {
            long totalSize = currentSize + upfile.Size;
            if (totalSize > AppSetting.MaxBoardAttachSize)
            {
                string errMsg = string.Format(GetLocalResourceObject("Msg11").ToString(), WebUtil.GetFormattedFileSize(AppSetting.MaxMailAttachSize));  // 첨부하려는 용량이 {0}를 초과하여 첨부할 수 없습니다.
                ScriptManager.RegisterClientScriptBlock(this, Page.GetType(), "ShowWarning", string.Format("ShowMessage('{0}');", errMsg), true);
                break;
            }
            else
            {
                string filePath = string.Format("{0}\\{1}{2}", GlobalConfig.WebTempPath, upfile.Uid, upfile.Extension);

                AttachmentEx attach = new AttachmentEx(upfile.Name, filePath);
                _attachments.Add(attach);
            }
        }

        ViewState["_attachments"] = _attachments;
        int attachCount = BindAttachmentsInfo();
        if (attachCount > 0) BootstrapUtil.CollapseControl(attachList, false);        // 첨부 파일이 있을 경우 숨김 해제
    }

    protected void RemoveAttachFileButton_Click(object sender, EventArgs e)
    {
        int index = int.Parse(RemoveAttachFileIndex.Value);
        _attachments[index].Deleted = true;
        ViewState["_attachments"] = _attachments;
        int attachCount = BindAttachmentsInfo();
        if (attachCount > 0) BootstrapUtil.CollapseControl(attachList, false);        // 첨부 파일이 있을 경우 숨김 해제
    }

    #endregion

    #region New, Reply and Modify

    private void InitNewArticle()
    {
        AuthorTextBox.Value = WebUser.CurrentUser.Name;
    }

    private void InitReplyArticle()
    {
        Article article = new Article(_articleId);
        article.Load();

        SubjectTextBox.Value = article.Subject;
        AuthorTextBox.Value = WebUser.CurrentUser.Name;
        MsgBodyHolder.Controls.Add(new LiteralControl(article.Body));
        SrcArticleView.Style["display"] = "inherit";
    }

    private void LoadModifyArticle(Article article)
    {
        SubjectTextBox.Value = article.Subject;
        AuthorTextBox.Value = article.AuthorName;
        MsgTextBox.Value = WebUtil.GetHtml4WebEditor(article.Body);
        foreach (Attachment attach in article.Attachments)
        {
            _attachments.Add(new AttachmentEx(attach.ID));
        }
        int attachCount = BindAttachmentsInfo();
        if (attachCount > 0) BootstrapUtil.CollapseControl(attachList, false);        // 첨부 파일이 있을 경우 숨김 해제
    }

    private List<Attachment> GetAttachments()
    {
        List<Attachment> addedList = new List<Attachment>();
        foreach (AttachmentEx item in _attachments)
        {
            if (!item.Deleted)
            {
                if (item.Type == Attachment.AttachType.Inline)
                    addedList.Add(new Attachment(item.ID, item.FileName, item.FilePath));
                else
                    addedList.Add(new Attachment(item.FileName, item.FilePath));
            }
        }
        return addedList;
    }

    private void GetAddedRemovedAttachments(out List<Attachment> added, out List<Attachment> removed)
    {
        added = new List<Attachment>();
        removed = new List<Attachment>();
        foreach (AttachmentEx item in _attachments)
        {
            if (!item.Deleted && item.NewAttach)
            {
                if (item.Type == Attachment.AttachType.Inline)
                    added.Add(new Attachment(item.ID, item.FileName, item.FilePath));
                else
                    added.Add(new Attachment(item.FileName, item.FilePath));
            }
        }

        foreach (AttachmentEx item in _attachments)
        {
            if (item.Deleted) removed.Add(new Attachment(item.ID));
        }
    }

    private string GetBodyHTML(string body, List<Attachment> attachments)
    {
        // <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEU 와 같은 인라인 이미지 태그를 인라인 이미지로 변환한다.
        string result = BoardUtil.ConvertBinaryImgTagToImgTag(body, attachments);

        // Copy & paste 이미지 입력 시 에디터 자체 기능으로 업로드한 경우(ckeditor, namose)
        // <img src="ViewInlineFile.ashx?id=filename.jpg">  ->  <img src="ViewInlineFile.ashx?id=guid">
        const string inlinePage = "ViewInlineFile.ashx?id=";
        string pattern = @"ViewInlineFile\x2eashx\x3fid=[\w\x2d\x28\x29\x3d]+\x2e[\w\x2d]+";
        Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
        Match m = r.Match(result);
        while (m.Success)
        {
            Guid fileId = Guid.NewGuid();
            string find = result.Substring(m.Index, m.Length);
            string fileName = find.Replace(inlinePage, "");
            string filePath = string.Format(@"{0}\{1}", GlobalConfig.WebShareTempPath, fileName);
            if (System.IO.File.Exists(filePath))
            {
                Attachment attachment = new Attachment(fileId, fileName, filePath);
                attachments.Add(attachment);

                string imgTag = string.Format("ViewInlineFile.ashx?id={0}", attachment.ID);
                result = result.Remove(m.Index, m.Length).Insert(m.Index, imgTag);
            }
            m = r.Match(result);
        }

        return result;
    }

    #endregion

    #region Internal Support Methods

    private long GetCurrentTotalAttachSize()
    {
        long totalSize = 0;
        foreach (AttachmentEx attach in _attachments)
        {
            if (!attach.Deleted) totalSize += attach.Size;
        }
        return totalSize;
    }

    private int BindAttachmentsInfo()
    {
        int attachCount = 0;
        long attachSize = 0;
        ExtIconMap iconMap = new ExtIconMap();
        StringBuilder attachSb = new StringBuilder();
        for (int i = 0; i < _attachments.Count; i++)
        {
            AttachmentEx attach = _attachments[i];
            if (!attach.Deleted)
            {
                string fileName = (attach.Type == Attachment.AttachType.Inline) ? "InlineImage" : attach.FileName;
                attachSb.Append(string.Format("<li class='list-group-item'><img src='../Images/Ext/{0}'/>{1} ({2}) <span class='fa-solid fa-xmark mc-likeLink' onclick=\"RemoveFile({3})\"></span></li>",
                    iconMap.GetIconName(attach.FilePath), fileName, WebUtil.GetFormattedFileSize(attach.Size), i));
                attachSize += attach.Size;
                attachCount++;
            }
        }
        AttachListTag.Text = attachSb.ToString();
        AttachSummaryLabel.Text = string.Format("{0}개 ({1})", attachCount, WebUtil.GetFormattedFileSize(attachSize));
        return attachCount;
    }

    private bool CheckPermitSize(Guid boardId)
    {
        long spaceAllowed, spaceUsed;

        UserBoard.GetSpaceInfo(WebUser.CurrentUser.DomainID, out spaceAllowed, out spaceUsed);
        if (spaceAllowed != -1 && spaceAllowed < spaceUsed)
        {
            return true;
        }
        return false;
    }

    #endregion
}