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.WebControls;
using TABS.MailCarrier.AuxLib;
using TABS.MailCarrier.WebSDK;
using TABS.MailCarrier.WebSDK.Mail;
using TABS.MailCarrier.WebSDK.Contact;
using TABS.MailCarrier.WebSDK.Filebox;
using TABS.MailCarrier.WebSDK.User;

/// <summary>
/// 새 메시지를 작성한다.
/// New.aspx?action=new
/// 파라미터: 
///    action: 필수
/// 
/// 회신 메시지를 작성한다.
/// New.aspx?action=reply&msg=ad71d630-8503-45d8-aac4-6d5b38117586&folder=c2986d84-d5de-4be6-8743-9ee31f985d60
/// 파라미터: 
///    action: 필수
///    msg: 필수, 메시지 ID
///    folder: 선택, 폴더 ID
/// 
/// 전체 회신 메시지를 작성한다. (모바일 미지원)
/// New.aspx?action=replyall&msg=ad71d630-8503-45d8-aac4-6d5b38117586|ad71d630-8503-45d8-aac4-6d5b38117586&folder=c2986d84-d5de-4be6-8743-9ee31f985d60
/// 파라미터: 
///    action: 필수
///    msg: 필수, 메시지 IDs, 구분자 |
///    folder: 선택, 폴더 ID
/// 
/// 전달 메시지를 작성한다.
/// New.aspx?action=forward&msg=ad71d630-8503-45d8-aac4-6d5b38117586&folder=c2986d84-d5de-4be6-8743-9ee31f985d60
/// 파라미터: 
///    action: 필수
///    msg: 필수, 메시지 ID
///    folder: 선택, 폴더 ID
/// 
/// 전체 전달 메시지를 작성한다. (모바일 미지원)
/// New.aspx?action=forward&msg=ad71d630-8503-45d8-aac4-6d5b38117586|ad71d630-8503-45d8-aac4-6d5b38117586&folder=c2986d84-d5de-4be6-8743-9ee31f985d60
/// 파라미터: 
///    action: 필수
///    msg: 필수, 메시지 IDs, 구분자 |
///    folder: 선택, 폴더 ID
/// 
/// 임시 편지함에 저장된 메시지를 로드하고 작성한다.
/// New.aspx?action=edit&msg=ad71d630-8503-45d8-aac4-6d5b38117586&folder=c2986d84-d5de-4be6-8743-9ee31f985d60
/// 파라미터: 
///    action: 필수
///    msg: 필수, 메시지 ID
///    folder: 선택, 폴더 ID
/// </summary>
public partial class Mail_NewTM : System.Web.UI.Page
{
    protected string _action;                   // 처리 방법
    protected Guid _msgId;                      // 메시지 ID
    protected Guid _folderId;                   // 폴더 ID

    protected string _initRecipientsScript = "";
    private AttachmentCollection _attachments = null;   // 첨부 파일 목록: ViewState에 저장    
    protected string _cssSenderName = "";       // 보내는 이름 UI를 숨기기 위한 css
    protected string _cssSenderAddr = "";       // 보내는 메일 주소 UI를 숨기기 위한 css
    protected string _signatureId = "";
    private string _htmlBody = "";

    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", "new");
        _msgId = WebParam.GetGuidParamValue("msg");
        _folderId = WebParam.GetGuidParamValue("folder");
        if (!AppSetting.UseSenderInfo)
            _cssSenderName = _cssSenderAddr = "collapse";

        if (!IsPostBack)
        {
            Page.Title = AppSetting.GetTitleInfo(Request).Title;
            // 임시 보관한 저장 시 사용할 ID
            ViewState["_tmpMsgId"] = (_action == "edit") ? _msgId : Guid.NewGuid();
            // 서명 첨부
            _signatureId = "SigId-" + ((Guid)ViewState["_tmpMsgId"]).ToString("N");
            _htmlBody = GetSignatureInfo();

            _attachments = new AttachmentCollection();
            ViewState["_attachments"] = _attachments;

            switch (_action)
            {
                case "new":
                    LoadToRcptsFromExtMenu();
                    if (AppSetting.UseSenderInfo && !AppSetting.UseDefaultSenderInfo)
                        LoadSenderName(null, null);
                    else
                        LoadSenderName(WebUser.CurrentUser.Name, WebUser.CurrentUser.MailAddress);
                    MsgTextBox.Value = _htmlBody;
                    break;
                case "reply":
                case "replyall":
                case "forward":
                case "edit":
                    LoadMailMessage(_msgId, "auto");
                    break;
            }
        }
        else
        {
            _attachments = (AttachmentCollection)ViewState["_attachments"];
        }
    }

    #region ASP.NET Event Handlers

    protected void SendButton_Click(object sender, EventArgs e)
    {
        SendMessage();
        Response.Redirect("List.aspx?init=true");       // 받은 편지함으로 이동
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        Guid msgId = (Guid)ViewState["_tmpMsgId"];
        SaveToTempFolder(msgId);
        if (_folderId == Guid.Empty)
            Response.Redirect("List.aspx?init=true");   // 받은 편지함으로 이동
        else 
            Response.Redirect(string.Format("List.aspx?folder={0}&init=true", _folderId.ToString()));
    }

    protected void AddAttachFileButton_Click(object sender, EventArgs e)
    {
        // 업로드된 파일 정보는 JsonUploadFilesHidden 변수에 JSON 문자열로 전달
        JavaScriptSerializer json = new JavaScriptSerializer();
        try
        {
            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.MaxMailAttachSize)
                {
                    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);
                    Attachment attach = new Attachment(upfile.Name, filePath, upfile.ContentType);
                    attach.Size = (int)upfile.Size;
                    _attachments.Add(attach);
                }
            }

            ViewState["_attachments"] = _attachments;
            BindAttachmentsInfo();
            if (_attachments.Count > 0 && attachList.Attributes["class"].IndexOf("in") == -1) BootstrapUtil.CollapseControl(attachList, false);        // 첨부 파일이 있을 경우 숨김 해제
        }
        catch (Exception ex)
        {
            LogWriter logw = new LogWriter(Request);
            logw.AddLogLine(string.Format("JsonUploadFilesHidden.Value: {0}", JsonUploadFilesHidden.Value));
            logw.AddException(ex);
            logw.Write();
        }
    }

    protected void RemoveAttachFileButton_Click(object sender, EventArgs e)
    {
        _attachments.RemoveAt(int.Parse(RemoveAttachFileIndex.Value));
        ViewState["_attachments"] = _attachments;
        BindAttachmentsInfo();
    }

    #endregion

    #region Send Message

    private void SendMessage()
    {
        WebUser.LoginInfo loginInfo = WebUser.CurrentUser;

        string charset = "utf-8";
        bool bSaveSent = true;

        List<RcptItem> toList, ccList, bccList;
        MakeRcptListFromJsonData(out toList, out ccList, out bccList);
        if (toList.Count == 0 && ccList.Count == 0 && bccList.Count == 0)
        {
            return;
        }

        NewMessage message = new NewMessage();
        message.TextBody = MsgTextBoxText.Value;
        message.Format = NewMessage.MessageFormat.Html;
        message.Priority = 3; // 보통
        message.Charset = charset;
        message.Encoding = NewMessage.MessageEncoding.Base64;
        message.FromName = SenderNameComboBox.SelectedItem.Text; 
        message.FromAddr = SenderAddrComboBox.SelectedItem.Text;
        message.Subject = SubjectTextBox.Value;
        message.ReplyTo = loginInfo.MailAddress;
        if (ViewState["Src-Message-ID"] != null)
        {
            message.InReplyTo = (string)ViewState["Src-Message-ID"];
            message.References = (string)ViewState["Src-Message-References"];
            if (message.References != "") message.References += "\r\n";
            message.References += (string)ViewState["Src-Message-ID"];
        }
        string bigFileHtml = "";
        SetAttachedFiles(message, true, out bigFileHtml);
        string editedHtml = HttpUtility.HtmlDecode(MsgTextBox.Value);
        message.HtmlBody = WebUtil.GetFullHtmlWithContainer(bigFileHtml + GetRelatedText(message, editedHtml));

        foreach (RcptItem item in toList)
        {
            if (item.Source == "email")
                message.To.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.To.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.To.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }
        foreach (RcptItem item in ccList)
        {
            if (item.Source == "email")
                message.Cc.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.Cc.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.Cc.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }
        foreach (RcptItem item in bccList)
        {
            if (item.Source == "email")
                message.Bcc.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.Bcc.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.Bcc.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }

        MsgExtender extender = new MsgExtender();
        extender.RcptItems.AddRange(toList);
        extender.RcptItems.AddRange(ccList);
        extender.RcptItems.AddRange(bccList);

        // TraceURL 설정 
        // http://mail.tabslab.com/Mail/ => http://mail.tabslab.com/External/ 로 변경
        string traceURL = WebParam.GetCurrentPageFullUrl();
        int idx = traceURL.LastIndexOf("/Mail/", StringComparison.OrdinalIgnoreCase);
        traceURL = string.Format("{0}/External", traceURL.Substring(0, idx));
        if (!AppSetting.EnableReadReceipt) traceURL = "";

        // 메일 발송 요청
        message.Send(bSaveSent, traceURL, loginInfo.DomainUserID, extender.MakeXml());
        // 메일 발송 로깅
        string toAddr = (message.To.Count > 0) ? message.To[0].Address : ((message.Cc.Count > 0) ? message.Cc[0].Address : "");
        WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Mail/NewMail.aspx", "SendMessage", string.Format("To:{0}", toAddr));

        if (_action == "edit")
        {
            Message message1 = new Message(_msgId);
            message1.Remove();
            // 작성된 메시지가 원 메시지(reply, replyall, forward)를 가진 경우 액션 플래그를 처리한다.
            if (ViewState["SourceMsgID"] != null)
            {
                Message message2 = new Message(new Guid((string)ViewState["SourceMsgID"]));
                message2.SetActionFlag(GetMsgActionFlag((string)ViewState["SourceMsgAction"]));
            }
        }
        else if (ViewState["_tmpMsgId"] != null)
        {
            Guid msgId = (Guid)ViewState["_tmpMsgId"];
            Message tmpMessage = new Message(msgId);
            tmpMessage.Remove();
        }
        else if (_action == "reply" || _action == "replyall" || _action == "forward" || _action == "forwardall")
        {
            Message message1 = new Message(_msgId);
            message1.SetActionFlag(GetMsgActionFlag(_action));
        }

        // 발송자 이름을 프로파일에 저장
        SenderNameList snlist = new SenderNameList(WebUser.CurrentProfile["SenderName"]);
        snlist.AddName(message.FromName);
        WebUser.CurrentProfile["SenderName"] = snlist.ToString();
        WebUser.CurrentProfile["SenderMailAddress"] = message.FromAddr;
        WebUser.CurrentProfile.Update();
    }

    #endregion

    #region Save to Temp Folder

    protected void SaveToTempFolder(Guid msgId)
    {
        WebUser.LoginInfo loginInfo = WebUser.CurrentUser;

        string charset = "utf-8";

        List<RcptItem> toList, ccList, bccList;
        MakeRcptListFromJsonData(out toList, out ccList, out bccList);

        NewMessage message = new NewMessage();
        message.Format = NewMessage.MessageFormat.Html;
        string editedHtml = HttpUtility.HtmlDecode(MsgTextBox.Value);
        message.HtmlBody = WebUtil.GetFullHtmlWithContainer(GetRelatedText(message, editedHtml));
        message.TextBody = "";
        message.Priority = 3; // 보통
        message.Charset = charset;
        message.Encoding = NewMessage.MessageEncoding.Base64;
        message.FromName = SenderNameComboBox.SelectedItem.Text;
        message.FromAddr = SenderAddrComboBox.SelectedItem.Text;
        message.Subject = SubjectTextBox.Value;
        string bigFileHtml = "";
        SetAttachedFiles(message, false, out bigFileHtml);

        foreach (RcptItem item in toList)
        {
            if (item.Source == "email")
                message.To.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.To.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.To.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }
        foreach (RcptItem item in ccList)
        {
            if (item.Source == "email")
                message.Cc.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.Cc.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.Cc.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }
        foreach (RcptItem item in bccList)
        {
            if (item.Source == "email")
                message.Bcc.Add(new Recipient(item.Name, item.Value));
            else if (item.Source == "contact")
                message.Bcc.Add(new Recipient(item.Name, Recipient.RecipientType.Group, new Guid(item.Value)));
            else if (item.Source == "orgz")
                message.Bcc.Add(new Recipient(item.Name, Recipient.RecipientType.OrgzItem, new Guid(item.Value)));
        }

        List<AdditionItem> additions = new List<AdditionItem>();
        additions.Add(new AdditionItem("SaveToSent", "true"));

        MsgExtender extender = new MsgExtender();
        extender.AdditionItems.AddRange(additions);
        extender.RcptItems.AddRange(toList);
        extender.RcptItems.AddRange(ccList);
        extender.RcptItems.AddRange(bccList);
        if (_action == "reply" || _action == "replyall" || _action == "forward")
        {
            // 회신/전달로 작성한 메시지를 임시 보관함에 저장 시 원 메시지 정보를 저장해 나중에 발송시 액션 플래그 처리가 가능하게 한다.
            extender.AdditionItems.Add(new AdditionItem("SourceMsgID", _msgId.ToString()));
            extender.AdditionItems.Add(new AdditionItem("SourceMsgAction", _action));
            extender.AdditionItems.Add(new AdditionItem("Src-Message-ID", (string)ViewState["Src-Message-ID"]));
            extender.AdditionItems.Add(new AdditionItem("Src-Message-References", (string)ViewState["Src-Message-References"]));
        }
        else if (_action == "edit" && ViewState["SourceMsgID"] != null)
        {
            // 임시 보관함에 저장된 메시지를 재로딩해 편집한 후 다시 저장한 경우로 원 메시지 정보를 저장해야 한다.
            extender.AdditionItems.Add(new AdditionItem("SourceMsgID", (string)ViewState["SourceMsgID"]));
            extender.AdditionItems.Add(new AdditionItem("SourceMsgAction", (string)ViewState["SourceMsgAction"]));
            extender.AdditionItems.Add(new AdditionItem("Src-Message-ID", (string)ViewState["Src-Message-ID"]));
            extender.AdditionItems.Add(new AdditionItem("Src-Message-References", (string)ViewState["Src-Message-References"]));
        }

        message.SaveTempFolder(WebUser.CurrentUser.DomainUserID, msgId, extender.MakeXml());

        // 발송자 이름을 프로파일에 저장
        SenderNameList snlist = new SenderNameList(WebUser.CurrentProfile["SenderName"]);
        snlist.AddName(message.FromName);
        WebUser.CurrentProfile["SenderName"] = snlist.ToString();
        WebUser.CurrentProfile["SenderMailAddress"] = message.FromAddr;
        WebUser.CurrentProfile.Update();
    }

    private class JsonRecipient
    {
        public string Name { get; set; }
        public string Type { get; set; }
        public string Value { get; set; }
        public bool Exist { get; set; }
    }

    /// <summary>
    /// ToRcptsHidden, CcRcptsHidden, BccRcptsHidden로부터 이메일 주소를 가져온다.
    /// </summary>
    /// <param name="toList"></param>
    /// <param name="ccList"></param>
    /// <param name="bccList"></param>
    private void MakeRcptListFromJsonData(out List<RcptItem> toList, out List<RcptItem> ccList, out List<RcptItem> bccList)
    {
        toList = new List<RcptItem>();
        ccList = new List<RcptItem>();
        bccList = new List<RcptItem>();

        try
        {
            JavaScriptSerializer json = new JavaScriptSerializer();
            List<JsonRecipient> jsonRecipientList = json.Deserialize<List<JsonRecipient>>(ToRcptsHidden.Value);
            foreach (JsonRecipient r in jsonRecipientList)
            {
                string source = "email";
                if (r.Type == "2") source = "contact";
                else if (r.Type == "3") source = "orgz";
                string name = (r.Name == r.Value) ? "" : r.Name;        // 표시 이름이 email 주소인 경우 표시 이름은 무시
                toList.Add(new RcptItem("to", name, r.Value, source));
            }
            jsonRecipientList = json.Deserialize<List<JsonRecipient>>(CcRcptsHidden.Value);
            foreach (JsonRecipient r in jsonRecipientList)
            {
                string source = "email";
                if (r.Type == "2") source = "contact";
                else if (r.Type == "3") source = "orgz";
                string name = (r.Name == r.Value) ? "" : r.Name;        // 표시 이름이 email 주소인 경우 표시 이름은 무시
                ccList.Add(new RcptItem("cc", name, r.Value, source));
            }
            jsonRecipientList = json.Deserialize<List<JsonRecipient>>(BccRcptsHidden.Value);
            foreach (JsonRecipient r in jsonRecipientList)
            {
                string source = "email";
                if (r.Type == "2") source = "contact";
                else if (r.Type == "3") source = "orgz";
                string name = (r.Name == r.Value) ? "" : r.Name;        // 표시 이름이 email 주소인 경우 표시 이름은 무시
                bccList.Add(new RcptItem("bcc", name, r.Value, source));
            }
        }
        catch (Exception ex)
        {
            LogWriter logw = new LogWriter(Request);
            logw.AddLogLine(string.Format("ToRcptsHidden.Value: {0}", ToRcptsHidden.Value));
            logw.AddLogLine(string.Format("CcRcptsHidden.Value: {0}", CcRcptsHidden.Value));
            logw.AddLogLine(string.Format("BccRcptsHidden.Value: {0}", BccRcptsHidden.Value));
            logw.AddException(ex);
            logw.Write();
        }
    }

    private void SetAttachedFiles(NewMessage message, bool bigFileToLink, out string bigFileHtml)
    {
        bigFileHtml = "";
        if (!bigFileToLink)
        {
            foreach (Attachment attach in _attachments)
            {
                message.Attachments.Add(new Attachment(WebUtil.InvalidAttachFileName(attach.FileName), attach.FilePath, attach.ContentType));
            }
        }
        else
        {
            int sumFileSize = 0;
            foreach (Attachment attach in _attachments)
            {
                sumFileSize += attach.Size;
                if (sumFileSize > AppSetting.SizeOfChangeToDownloadLink)
                {
                    // 용량이 15MB를 초과하는 경우 링크 방식으로 변경
                    FileboxFolder folder = new FileboxFolder(new Guid(FileboxFolder.MailTempFileboxFolderID));
                    FileboxFile file = new FileboxFile();
                    file.Name = attach.FileName;
                    file.Size = attach.Size;
                    file.Description = "";
                    file.Creator = WebUser.CurrentUser.UserAccount;
                    file.CreateTime = DateTime.UtcNow;
                    Guid fileId = folder.AddFile(file, attach.FilePath, WebUser.CurrentUser.DomainUserID);

                    FileboxFile linkedFile = new FileboxFile(fileId);
                    linkedFile.Load();

                    int validHour = AppSetting.FileboxLinkValidHour;
                    DateTime availableTime = DateTime.Now.AddHours(validHour);
                    string param = linkedFile.GetEncodedParam2(availableTime);
                    string pageURL = WebParam.GetCurrentPageFullUrl();
                    int idx = pageURL.ToLower().LastIndexOf("/mail/");
                    pageURL = string.Format("{0}/External/", pageURL.Substring(0, idx));
                    string url = string.Format("{0}FileboxDownload.ashx?encodedParam2={1}", pageURL, param);

                    if (bigFileHtml != "") bigFileHtml += "<br />";
                    bigFileHtml += string.Format(GetLocalResourceObject("DownloadLink").ToString(), url, file.Name, availableTime, WebUtil.GetFormattedFileSize(file.Size));
                }
                else
                {
                    message.Attachments.Add(new Attachment(WebUtil.InvalidAttachFileName(attach.FileName), attach.FilePath, attach.ContentType));
                }
            }

            if (bigFileHtml != "")
            {
                bigFileHtml = string.Format("<div style='border: 1px solid #cccccc; padding: 5px'>{0}</div><br /><br />", bigFileHtml);
            }
        }
    }

    private string GetRelatedText(NewMessage message, string html)
    {
        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(html);

        while (m.Success)
        {
            string find = html.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(fileName, filePath);
                message.Inlines.AddUnique(attachment);
            }
            m = m.NextMatch();
        }

        // "ViewInlineFile.ashx?id="를 제거한다.
        html = html.Replace(inlinePage, "");

        // 메일 보기 페이지에 있는 inline attachment 파일을 드래그&드롭(또는 Copy&Paste)으로 가져왔을 경우 아래와 같은 태그가 생성된다.
        // <img alt="" src="http://webaccess7.tabslab.com/Mail/Download.ashx?content=628de0ad64dc45b3914e5723c64984c3-597-1.png" />
        // 이를 inline attachment가 되도록 수정한다.
        bool existDownloadPage = false;
        const string downloadPage = "Download.ashx?content=";
        pattern = @"Download\x2eashx\x3fcontent=[\w\x2d\x28\x29\x3d]+\x2e[\w\x2d]+";
        r = new Regex(pattern, RegexOptions.IgnoreCase);
        m = r.Match(html);
        while (m.Success)
        {
            string find = html.Substring(m.Index, m.Length);
            string fileName = find.Replace(downloadPage, "");
            string filePath = string.Format(@"{0}\{1}", GlobalConfig.WebShareTempPath, fileName);
            if (System.IO.File.Exists(filePath))
            {
                Attachment attachment = new Attachment(fileName, filePath);
                message.Inlines.AddUnique(attachment);
                existDownloadPage = true;
            }
            m = m.NextMatch();
        }
        if (existDownloadPage)
        {
            // "http://webaccess7.tabslab.com/Mail/Download.ashx?content="를 제거한다.
            string findUrl = WebParam.GetCurrentPageFullUrl() + downloadPage;
            html = html.Replace(findUrl, "");
        }

        // <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEU 와 같은 인라인 이미지 태그를 메일 인라인 이미지로 변환한다.
        html = MailUtil.ConvertBinaryImgTagToCidImgTag(html, message);
        return html;
    }

    private Message.MsgActionFlag GetMsgActionFlag(string action)
    {
        if (action == "reply")
            return Message.MsgActionFlag.Reply;
        else if (action == "replyall")
            return Message.MsgActionFlag.ReplyAll;
        else if (action == "forward" || action == "forwardall")
            return Message.MsgActionFlag.Forward;
        else if (action == "edit")
            return Message.MsgActionFlag.Editing;
        return Message.MsgActionFlag.NoAction;
    }

    #endregion

    #region Show Message for Edit, Reply and Forward

    private void LoadMailMessage(Guid msgId, string charset)
    {
        Message message = new Message(msgId);

        // msg가 본인 소유의 것인지 검사한다.
        if (!message.IsMine(WebUser.CurrentUser.DomainUserID))
        {
            Response.Redirect("~/Error.aspx?code=2", true);
            return;
        }

        try
        {
            if (_action == "edit")
                message.Load(false, true);      // 편집 모드로 로딩 시 캐시를 지워야 현재 eml의 첨부 파일이 로딩된다. 캐시가 남아 있을 경우 이전 첨부가 로딩될 수 있다.
            else 
                message.Load();

            string charSet = (message.TextCharset != "") ? message.TextCharset : message.HtmlCharset;
            ShowMailMessage(message);
            if (_action == "edit")
            {
                LoadSenderName(message.FromName, message.FromAddress);
            }
            else
            {
                if (AppSetting.UseSenderInfo && !AppSetting.UseDefaultSenderInfo)
                    LoadSenderName(null, null);
                else
                    LoadSenderName(WebUser.CurrentUser.Name, WebUser.CurrentUser.MailAddress);
            }
        }
        catch (LoadFailException)
        {
        }
    }

    private void ShowMailMessage(Message message)
    {
        ShowMailMessageHeader(message);

        // reply, replyall 일 경우에 ViewState["Message-ID"] = Message-ID;
        SaveMessageID(message);

        bool relatedAttach = ShowMailMessageAttachedFiles(message);

        ShowMailMessageBody(message, relatedAttach, (_action != "edit"));
    }

    /// <summary>
    /// 메시지 헤더를 출력한다.
    ///    - From, To, Cc, Bcc, Subject
    /// </summary>
    /// <param name="message"></param>
    private void ShowMailMessageHeader(Message message)
    {
        bool existRe = (message.Subject.ToLower().IndexOf("re:") == 0);
        if (_action == "reply")
        {
            if (message.ReplyToEx.Length > 0)
            {
                foreach (Recipient recipient in message.ReplyToEx)
                {
                    _initRecipientsScript += string.Format("toRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(recipient.Name), WebUtil.EncodeJsString2(recipient.Address));
                }
            }
            else
            {
                _initRecipientsScript += string.Format("toRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(message.FromName), WebUtil.EncodeJsString2(message.FromAddress));
            }
            // 회신시 RE:는 제일 앞 하나만을 허용한다.
            if (!existRe) SubjectTextBox.Value = "RE: ";
        }
        else if (_action == "replyall")
        {
            if (message.ReplyToEx.Length > 0)
            {
                foreach (Recipient recipient in message.ReplyToEx)
                {
                    _initRecipientsScript += string.Format("toRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(recipient.Name), WebUtil.EncodeJsString2(recipient.Address));
                }
            }
            else
            {
                _initRecipientsScript += string.Format("toRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(message.FromName), WebUtil.EncodeJsString2(message.FromAddress));
            }
            foreach (Recipient recipient in message.To)
            {
                if (recipient.Address != WebUser.CurrentUser.MailAddress)
                {
                    _initRecipientsScript += string.Format("toRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(recipient.Name), WebUtil.EncodeJsString2(recipient.Address));
                }
            }
            foreach (Recipient recipient in message.Cc)
            {
                _initRecipientsScript += string.Format("ccRcpts.AddMailAddress('{0}', '{1}');", WebUtil.EncodeJsString2(recipient.Name), WebUtil.EncodeJsString2(recipient.Address));
            }
            // 회신시 RE:는 제일 앞 하나만을 허용한다.
            if (!existRe) SubjectTextBox.Value = "RE: ";
        }
        else if (_action == "forward")
        {
            SubjectTextBox.Value = "FW: ";
        }
        else if (_action == "edit")
        {
            // EtcConfig로부터 정보를 읽어온다.
            ShowMailMessageHeaderFromMsgExtender(message);
        }
        SubjectTextBox.Value += message.Subject;
    }

    // <summary>
    /// 원본 메시지로부터 Message-ID를 가져와서 임시저장한다.
    /// 회신할 경우 In-Reply-To: Src-Message-ID값을 지정한다.
    /// </summary>
    /// <param name="mailParser"></param>
    private void SaveMessageID(Message message)
    {
        if (_action == "reply" || _action == "replyall")
        {
            ViewState["Src-Message-ID"] = message.GetHeader("Message-ID");
            ViewState["Src-Message-References"] = message.GetHeader("References");
        }
    }

    /// <summary>
    /// 메시지 첨부파일을 출력한다.
    ///    - 첨부파일, 인라인 컨텐츠 처리
    /// </summary>
    /// <param name="message"></param>
    private bool ShowMailMessageAttachedFiles(Message message)
    {
        bool relatedAttach = false;

        if (_action == "forward" || _action == "edit")
        {
            if (message.AttachCount > 0)
            {
                foreach (Attachment attachment in message.Attachments)
                {
                    if (attachment.ContentID != "" && (attachment.Type == Attachment.AttachType.Inline || message.HtmlBody.IndexOf(attachment.ContentID) > 0))
                    {
                        relatedAttach = true;
                    }
                    else
                    {
                        // message.Attachments의 FilePath에는 완전한 경로를 반환하지 않으므로 재구성할 필요가 있다.
                        Attachment newAttach = new Attachment(attachment.FileName, string.Format(@"{0}\{1}", GlobalConfig.WebShareTempPath, attachment.FilePath), attachment.ContentType);
                        newAttach.Size = attachment.Size;
                        _attachments.Add(newAttach);
                    }
                }
                
                ViewState["_attachments"] = _attachments;
                BindAttachmentsInfo();
                if (_attachments.Count > 0) BootstrapUtil.CollapseControl(attachList, false);        // 첨부 파일이 있을 경우 숨김 해제
            }
        }
        else if (_action == "reply" || _action == "replyall")
        {
            if (message.AttachCount > 0)
            {
                foreach (Attachment attachment in message.Attachments)
                {
                    if (attachment.ContentID != "" && attachment.Type == Attachment.AttachType.Inline)
                    {
                        relatedAttach = true;
                    }
                    else if (attachment.ContentType == "application/ms-tnef")
                    {
                        // 첨부로 처리하지 않음
                    }
                }
            }
        }
        return relatedAttach;
    }

    /// <summary>
    /// 메시지 본문을 출력한다.
    /// </summary>
    /// <param name="message"></param>
    /// <param name="insertHeader">
    /// 회신, 전체회신, 전달시 이전메시지 헤더에 대한 정보를 저장할 것인지의 여부
    /// </param>
    private void ShowMailMessageBody(Message message, bool relatedAttach, bool insertHeader)
    {
        // 본문 출력
        if (message.HtmlBody != "")
        {
            string html = WebUtil.GetHtml4WebEditor(message.HtmlBody);

            if (relatedAttach)
            {
                Array.Sort<Attachment>(message.Attachments, new Comparison<Attachment>((i1, i2) => i2.ContentID.CompareTo(i1.ContentID)));
                foreach (Attachment attach in message.Attachments)
                {
                    if (attach.ContentID != "")
                    {
                        string cid = "cid:" + attach.ContentID;
                        string downlink = string.Format("ViewInlineFile.ashx?id={0}", attach.FilePath);
                        html = html.Replace(cid, downlink);
                    }
                }
            }
            if (insertHeader)
            {
                _htmlBody += NewMsgUtil.GetFormattedMessageHeaderHtml(message) + "<p>&nbsp;</p>" + html;
            }
            else
            {
                _htmlBody += html;
            }
        }
        else
        {
            string html = WebUtil.GetFormattedPlainText(message.TextBody, true);
            if (insertHeader)
            {
                _htmlBody += NewMsgUtil.GetFormattedMessageHeaderHtml(message) + "<p>&nbsp;</p>" + html;
            }
            else
            {
                _htmlBody += html;
            }
        }
        MsgTextBox.Value = _htmlBody;
    }

    private void ShowMailMessageHeaderFromMsgExtender(Message message)
    {
        string xml = message.UserDefinedXml;
        if (xml != "")
        {
            MsgExtender extender = new MsgExtender();
            extender.LoadFromXml(xml);

            if (extender.RcptItems.Count > 0)
            {
                string addMailAddressFormat = "{0}.AddMailAddress('{1}', '{2}');";
                string addOrgzFormat = "{0}.AddOrgz('{1}', '{2}');";
                string addMailGroupFormat = "{0}.AddMailGroup('{1}', '{2}');";

                foreach (RcptItem item in extender.RcptItems)
                {
                    if (item.Source == "orgz")
                    {
                        switch (item.Type)
                        {
                            case "to":
                                _initRecipientsScript += string.Format(addOrgzFormat, "toRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "cc":
                                _initRecipientsScript += string.Format(addOrgzFormat, "ccRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "bcc":
                                _initRecipientsScript += string.Format(addOrgzFormat, "bccRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                        }
                    }
                    else if (item.Source == "contact")
                    {
                        switch (item.Type)
                        {
                            case "to":
                                _initRecipientsScript += string.Format(addMailGroupFormat, "toRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "cc":
                                _initRecipientsScript += string.Format(addMailGroupFormat, "ccRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "bcc":
                                _initRecipientsScript += string.Format(addMailGroupFormat, "bccRcpts", WebUtil.EncodeJsString2(item.Name), WebUtil.EncodeJsString2(item.Value));
                                break;
                        }
                    }
                    else if (item.Source == "email")
                    {
                        string name = (item.Name == "") ? item.Value : item.Name;       // 표시 이름이 비어 있으면 메일 주소로 대체
                        switch (item.Type)
                        {
                            case "to":
                                _initRecipientsScript += string.Format(addMailAddressFormat, "toRcpts", WebUtil.EncodeJsString2(name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "cc":
                                _initRecipientsScript += string.Format(addMailAddressFormat, "ccRcpts", WebUtil.EncodeJsString2(name), WebUtil.EncodeJsString2(item.Value));
                                break;
                            case "bcc":
                                _initRecipientsScript += string.Format(addMailAddressFormat, "bccRcpts", WebUtil.EncodeJsString2(name), WebUtil.EncodeJsString2(item.Value));
                                break;
                        }
                    }
                }
            }
            // 메시지 로딩 시 extender에 저장되어 있는 원 메시지 정보를 ViewState로 옮겨서 발송/저장(SendMessage/SaveTempMessage) 시 참조할 수 있도록 한다.
            string sourceMsgId = extender.GetAddtionItemValue("SourceMsgID");
            if (sourceMsgId != "")
            {
                ViewState["SourceMsgID"] = sourceMsgId;
                ViewState["SourceMsgAction"] = extender.GetAddtionItemValue("SourceMsgAction");
                ViewState["Src-Message-ID"] = extender.GetAddtionItemValue("Src-Message-ID");
                ViewState["Src-Message-References"] = extender.GetAddtionItemValue("Src-Message-References");
            }
        }
    }

    private void BindAttachmentsInfo()
    {
        int attachSize = 0;
        ExtIconMap iconMap = new ExtIconMap();
        StringBuilder attachSb = new StringBuilder();
        for (int i = 0; i < _attachments.Count; i++)
        {
            Attachment attach = _attachments[i];
            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), attach.FileName, WebUtil.GetFormattedFileSize(attach.Size), i));
            attachSize += attach.Size;
        }
        AttachListTag.Text = attachSb.ToString();
        AttachSummaryLabel.Text = string.Format("{0}개 ({1})", _attachments.Count, WebUtil.GetFormattedFileSize((long)attachSize));
    }

    #endregion

    #region Internal Support Methods

    /// <summary>
    /// 서명 정보를 반환한다.
    /// </summary>
    /// <returns></returns>
    private string GetSignatureInfo()
    {
        string sign = "";
        TABS.MailCarrier.WebSDK.User.DomainUser domainUser =
            new TABS.MailCarrier.WebSDK.User.DomainUser(WebUser.CurrentUser.DomainUserID);
        Signature signature = domainUser.Signature;
        if (signature.Apply)
        {
            if (_action == "new" || (signature.ApplyForReplyForward && (_action == "forward" || _action == "reply" || _action == "replyall")))
            {
                if (GlobalConfig.SchemaVersion < 752 && signature.Text.Trim().Length > 0)
                {
                    sign = string.Format("<p>&nbsp;</p>{0}", signature.Html);
                }
                else
                {
                    // 기본 서명을 찾아서 지정한다.
                    foreach (SignatureEx sig in domainUser.SignatureEx)
                    {
                        if ((sig.Flag & SignatureEx.SigFlagType.Default) > 0)
                        {
                            sign = string.Format("<p>&nbsp;</p><p>&nbsp;</p><div id=\"{0}\">{1}</div><p>&nbsp;</p>", _signatureId, sig.Html.Replace("id=\"mc_container\"", ""));
                            break;
                        }
                    }
                }
            }
        }
        // 메일 꼬리글이 정의되어 있을 경우 출력한다.
        AppSetting.TitleInfo ti = AppSetting.GetTitleInfo(Request);
        if (ti["mailtailphrase"] != "") sign += ti["mailtailphrase"];
        return sign;
    }

    private int GetCurrentTotalAttachSize()
    {
        int totalSize = 0;
        foreach (Attachment attach in _attachments)
        {
            totalSize += attach.Size;
        }
        return totalSize;
    }

    /// <summary>
    /// 주소록/조직도 등에서 메일 쓰기를 호출 시 수신자(to) 부분을 채우기 위해 사용된다.
    /// </summary>
    private void LoadToRcptsFromExtMenu()
    {
        _initRecipientsScript = "";

        if (WebParam.GetStrParamValue("to") != "")
        {
            string to = WebParam.GetStrParamValue("to");
            string name = to.Split('|')[0];
            string emailAddr = to.Split('|')[1];
            _initRecipientsScript += string.Format("CallReturnToRecipients('{0}', '{1}', 1);", WebUtil.EncodeJsString2(name), WebUtil.EncodeJsString2(emailAddr));
            return;
        }

        // 주소록에서 메일 쓰기시
        Guid contactId = WebParam.GetGuidParamValue("contact");
        int prefer = WebParam.GetIntParamValue("prefer", 0);
        if (contactId != Guid.Empty)
        {
            Contact contact = new Contact(contactId);
            contact.Load();
            if (contact.Type == Contact.ContactType.Contact)
            {
                string emailAddr = (prefer == 0) ? contact.Email : (prefer == 1) ? contact.Email2 : contact.Email3;
                _initRecipientsScript += string.Format("CallReturnToRecipients('{0}', '{1}', 1);", WebUtil.EncodeJsString2(contact.DisplayName), WebUtil.EncodeJsString2(emailAddr));
            }
            else
            {
                _initRecipientsScript += string.Format("CallReturnToRecipients('{0}', '{1}', 2);", WebUtil.EncodeJsString2(contact.DisplayName), contact.ID);
            }
            return;
        }
        // 조직도 멤버에서 메일 쓰기시 -> 미지원
        //Guid memberId = WebParam.GetGuidParamValue("member");
        //if (memberId != Guid.Empty)
        //{
        //    TABS.MailCarrier.WebSDK.User.DomainUser member =
        //        new TABS.MailCarrier.WebSDK.User.DomainUser(memberId);
        //    string displayName = string.Format("#[{0}]", member.Name);
        //    script += string.Format("CallReturnToRecipients('{0}', '{1}', 3);", displayName, memberId);
        //}

        // 조직도 그룹에서 메일 쓰기시 -> 미지원
        //Guid orzPartId = WebParam.GetGuidParamValue("part");
        //if (orzPartId != Guid.Empty)
        //{
        //    OrganizationPart part = new OrganizationPart(orzPartId);
        //    part.Load();
        //    string displayName = string.Format("#[{0}]", part.Name);
        //    script += string.Format("CallReturnToRecipients('{0}', '{1}', 3);", displayName, part.ID);
        //}
        //return script;
    }

    #endregion

    #region SenderName Management

    private void LoadSenderName(string senderName, string senderAddr)
    {
        SenderAddrComboBox.Items.Add(new ListItem(WebUser.CurrentUser.MailAddress));
        foreach (string aliasAddress in WebUser.CurrentUser.AliasMailAddresses)
            SenderAddrComboBox.Items.Add(new ListItem(aliasAddress));
        string senderAddress = (senderAddr != null) ? senderAddr : WebUser.CurrentProfile["SenderMailAddress"];
        foreach (ListItem item in SenderAddrComboBox.Items)
            if (string.Compare(item.Text, senderAddress, true) == 0) { item.Selected = true; break; }
        if (SenderAddrComboBox.Items.Count == 1) _cssSenderAddr = "collapse";

        SenderNameList snlist = new SenderNameList(WebUser.CurrentProfile["SenderName"], WebUser.CurrentUser.Name);
        WebUser.CurrentProfile["SenderName"] = snlist.ToString();
        foreach (SenderNameList.Item item in snlist.GetDataSource())
            SenderNameComboBox.Items.Add(item.Name);
        if (senderName == null) senderName = snlist.GetFirstName();
        ListItem selectItem = SenderNameComboBox.Items.FindByText(senderName);
        if (selectItem != null)
        {
            selectItem.Selected = true;
        }
        else
        {
            SenderNameComboBox.Items.Add(WebUser.CurrentUser.Name);
            SenderNameComboBox.Items.FindByText(WebUser.CurrentUser.Name).Selected = true;
        }

        bool addDelim = false;
        StringBuilder sb = new StringBuilder();
        sb.Append("var autoCmplSenderArray = new Array(");
        foreach (SenderNameList.Item item in snlist.GetDataSource())
        {
            if (addDelim) sb.Append(",");
            else addDelim = true;
            sb.Append(string.Format("'{0}'", WebUtil.EncodeJsString2(item.Name)));
        }
        sb.Append(");");
        if (!ClientScript.IsClientScriptBlockRegistered(this.GetType(), "autoCompleteSender"))
            ClientScript.RegisterClientScriptBlock(this.GetType(), "autoCompleteSender", sb.ToString(), true);
    }

    #endregion
    
}