using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Web;
using System.Web.Security;
using System.Xml;
using TABS.MailCarrier.Crypt;
using TABS.MailCarrier.StgBase;
using TABS.MailCarrier.WebSDK;
using TABS.MailCarrier.WebSDK.Calendar;

namespace NotifyGenericHandler
{
    public class Redirect
    {
        private HttpContext _context;

        public void ProcessRequest(HttpContext context)
        {
            _context = context;
            string encAuth = WebParam.GetStrParamValue("auth");
            string returnUrl = context.Server.UrlDecode(WebParam.GetStrParamValue("ReturnUrl"));

            string auth;
            if (CryptData.Decrypt(encAuth, out auth))
            {
                string key, mailAddr, password;
                if (GetAuthParam(auth, out key, out mailAddr, out password))
                {
                    if (IsValidKey(key))
                    {
                        Guid domainUserId, domainId;
                        if (Login(mailAddr, password, out domainUserId, out domainId))
                        {
                            // 사용자를 로그 아웃시킨다.
                            FormsAuthentication.SignOut();
                            // 로그인 세션을 제거한다.
                            WebUser.ExpireSession();

                            WriteWebAccessLog(domainId, 1, mailAddr);

                            // 새로 로그인한다.
                            FormsAuthentication.RedirectFromLoginPage(domainUserId.ToString(), false);
                            return;
                        }
                        else
                        {
                            WriteWebAccessLog(domainId, 3, mailAddr);
                        }

                    }
                }
            }
            context.Response.Redirect("~/");
        }

        private bool GetAuthParam(string auth, out string key, out string mailAddr, out string password)
        {
            key = "";
            mailAddr = "";
            password = "";

            int i = auth.IndexOf('|');
            if (i != -1)
            {
                key = auth.Substring(0, i);
                int j = auth.IndexOf('|', i + 1);
                if (j != -1)
                {
                    mailAddr = auth.Substring(i + 1, j - i - 1);
                    j++;
                    int k = auth.IndexOf('\0', j);
                    password = auth.Substring(j, k - j);
                    return true;
                }
            }

            return false;
        }

        private bool IsValidKey(string key)
        {
            DateTime serverTime;
            if (CryptData.Decrypt(key, out serverTime))
            {
                TimeSpan ts = DateTime.Now.Subtract(serverTime);
                return ts.Minutes < 3;
            }
            return false;
        }

        private bool Login(string mailAddr, string password, out Guid domainUserId, out Guid domainId)
        {
            domainUserId = Guid.Empty;
            domainId = Guid.Empty;
            string[] m = mailAddr.Split('@');
            if (m.Length == 2)
            {
                string userId = m[0];
                string domain = m[1];

                SqlConnection conn = new SqlConnection(GlobalConfig.ConnString);
                DataSet ds = Mcsp.McDomainUserSelectByUser(conn, userId, domain);
                if (ds.Tables[0].Rows.Count == 1)
                {
                    DataRow row = ds.Tables[0].Rows[0];
                    domainId = (Guid)row["dm_id"];

                    Mcsp.UserStatusFlag status = (Mcsp.UserStatusFlag)row["du_status"];
                    Mcsp.UserServiceFlag service = (Mcsp.UserServiceFlag)row["du_permitProtocol"];
                    bool permitWebAccess = (service & Mcsp.UserServiceFlag.WebMail) > 0;
                    string cmpPwd = (string)row["du_pwd"];
                    if (((status & Mcsp.UserStatusFlag.Use) > 0) && permitWebAccess && cmpPwd != null && password == cmpPwd)
                    {
                        domainUserId = (Guid)row["du_id"];
                        return true;
                    }
                }
            }
            return false;
        }

        protected void WriteWebAccessLog(Guid domainId, int operation, string loginAddr)
        {
            SqlConnection conn = new SqlConnection(GlobalConfig.ConnString);
            try
            {
                conn.Open();
                Mcsp.McWebAccessLogInsert(conn, null, domainId, _context.Request.UserHostAddress, operation, loginAddr);
            }
            finally
            {
                conn.Close();
            }
        }
    }

    public class LogonBase
    {
        protected HttpContext _context;

        public LogonBase(HttpContext context)
        {
            _context = context;
        }

        protected bool Login(string mailAddr, out Guid domainUserId, out Guid domainId)
        {
            domainUserId = Guid.Empty;
            domainId = Guid.Empty;
            string[] m = mailAddr.Split('@');
            if (m.Length == 2)
            {
                string userId = m[0];
                string domain = m[1];

                using (SqlConnection conn = new SqlConnection(GlobalConfig.ConnString))
                {
                    DataSet ds = Mcsp.McDomainUserSelectByUser(conn, userId, domain);
                    if (ds.Tables[0].Rows.Count == 1)
                    {
                        DataRow row = ds.Tables[0].Rows[0];
                        domainId = (Guid)row["dm_id"];

                        Mcsp.UserStatusFlag status = (Mcsp.UserStatusFlag)row["du_status"];
                        if (((status & Mcsp.UserStatusFlag.Use) > 0))
                        {
                            domainUserId = (Guid)row["du_id"];
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        protected void WriteWebAccessLog(Guid domainId, int operation, string loginAddr)
        {
            SqlConnection conn = new SqlConnection(GlobalConfig.ConnString);
            try
            {
                conn.Open();
                Mcsp.McWebAccessLogInsert(conn, null, domainId, _context.Request.UserHostAddress, operation, loginAddr);
            }
            finally
            {
                conn.Close();
            }
        }

        protected void WriteWebAccessLog(Guid domainId, int operation, int subOperation, string loginAddr)
        {
            SqlConnection conn = new SqlConnection(GlobalConfig.ConnString);
            try
            {
                conn.Open();
                if (GlobalConfig.SchemaVersion < 757)
                    Mcsp.McWebAccessLogInsert(conn, null, domainId, _context.Request.UserHostAddress, operation, loginAddr);
                else
                    Mcsp.McWebAccessLogInsertEx(conn, null, domainId, _context.Request.UserHostAddress, operation, subOperation, loginAddr);
            }
            catch
            {
            }
            finally
            {
                conn.Close();
            }
        }

        protected void WriteLoginInfo(Guid domainUserId, string clientIp)
        {
            if (GlobalConfig.SchemaVersion < 752) return;
            SqlConnection conn = new SqlConnection(GlobalConfig.ConnString);
            try
            {
                conn.Open();
                Mcsp.McLoginInfoUpdate(conn, null, domainUserId, SqlString.Null, SqlString.Null, SqlString.Null, clientIp);
            }
            catch
            {
            }
            finally
            {
                conn.Close();
            }
        }

        protected void SetLanguage(string lang)
        {
            if (!(lang == "ko" || lang == "en" || lang == "zh"))
            {
                lang = "ko";
            }
            _context.Response.Cookies["DefaultLanguage"].Value = lang;
            _context.Response.Cookies["DefaultLanguage"].Expires = DateTime.Now.AddDays(3650);
        }

        protected void SetTimeZone(string timeZoneId)
        {
            if (AppSetting.UseTimeZone)
            {
                _context.Response.Cookies["DefaultTimeZone"].Value = timeZoneId;
                _context.Response.Cookies["DefaultTimeZone"].Expires = DateTime.Now.AddDays(3650);
            }
            else
            {
                _context.Response.Cookies["DefaultTimeZone"].Value = "";
            }
        }
    }

    public class Logon : LogonBase
    {
        public Logon(HttpContext context)
            : base(context)
        {
        }

        public void ProcessRequest()
        {
            if (!AppSetting.EnableSsoUsingReferer)
            {
                _context.Response.Redirect("~/");
                return;
            }

            string user = WebParam.GetStrParamValue("User");
            string returnUrl = _context.Server.UrlDecode(WebParam.GetStrParamValue("ReturnUrl"));
            string lang = WebParam.GetStrParamValue("Lang");
            string timeZoneId = WebParam.GetStrParamValue("Tz");

            HttpRequest request = _context.Request;
            string referer = request.ServerVariables["HTTP_REFERER"];
            referer = (referer == null) ? "" : referer.ToLower();
            string xmlFile = _context.Server.MapPath("~/App_Data/referer.xml");
            string clientIp = request.UserHostAddress;
            AppSetting.TitleInfo titleInfo = AppSetting.GetTitleInfo(request.Headers["Host"]);

            XmlDocument xml = new XmlDocument();
            try
            {
                xml.Load(xmlFile);
                foreach (XmlNode childNode in xml.DocumentElement.ChildNodes)
                {
                    if (childNode.Name == "site" && childNode.InnerText.Length > 0)
                    {
                        if (referer.IndexOf(childNode.InnerText) != -1)
                        {
                            if (titleInfo.IsAcceptedIP(clientIp))
                            {
                                Guid domainUserId, domainId;
                                if (Login(user, out domainUserId, out domainId))
                                {
                                    // 사용자를 로그 아웃시킨다.
                                    FormsAuthentication.SignOut();
                                    // 로그인 세션을 제거한다.
                                    WebUser.ExpireSession();

                                    WriteWebAccessLog(domainId, 1, user);
                                    WriteLoginInfo(domainUserId, clientIp);

                                    // 새로 로그인한다.
                                    FormsAuthentication.RedirectFromLoginPage(domainUserId.ToString(), false);

                                    SetLanguage(lang);
                                    SetTimeZone(timeZoneId);
                                    return;
                                }
                                else
                                {
                                    WriteWebAccessLog(domainId, 3, 1, user);
                                }
                            }
                            else
                            {
                                _context.Response.Redirect("~/Error.aspx?code=22");
                            }
                            break;
                        }
                    }
                }
            }
            catch
            {
            }
            _context.Response.Redirect("~/");
        }
    }

    /// <summary>
    /// LogonEx.ashx?Token=DSDF..DCF3&ReturnUrl=%2fDefault.aspx
    /// </summary>
    public class LogonEx : LogonBase
    {
        public LogonEx(HttpContext context)
            : base(context)
        {
        }

        public void ProcessRequest()
        {
            if (!AppSetting.EnableSsoUsingSecureToken)
            {
                _context.Response.Redirect("~/");
                return;
            }

            string encToken = WebParam.GetStrParamValue("Token");
            string returnUrl = _context.Server.UrlDecode(WebParam.GetStrParamValue("ReturnUrl"));
            string lang = WebParam.GetStrParamValue("Lang");
            string timeZoneId = WebParam.GetStrParamValue("Tz");

            string mailAddress = "";
            if (!TABS.MailCarrier.Crypt.SingleSignOn.IsValidLogonTokenEx(AppSetting.SingleSignOnPassword, encToken, out mailAddress))
            {
                _context.Response.Redirect("~/");
                return;
            }

            HttpRequest request = _context.Request;
            string clientIp = request.UserHostAddress;
            AppSetting.TitleInfo titleInfo = AppSetting.GetTitleInfo(request.Headers["Host"]);

            if (titleInfo.IsAcceptedIP(clientIp))
            {
                Guid domainUserId, domainId;
                if (Login(mailAddress, out domainUserId, out domainId))
                {
                    // 사용자를 로그 아웃시킨다.
                    FormsAuthentication.SignOut();
                    // 로그인 세션을 제거한다.
                    WebUser.ExpireSession();

                    WriteWebAccessLog(domainId, 1, mailAddress);
                    WriteLoginInfo(domainUserId, clientIp);

                    // 새로 로그인한다.
                    FormsAuthentication.RedirectFromLoginPage(domainUserId.ToString(), false);

                    SetLanguage(lang);
                    SetTimeZone(timeZoneId);
                    return;
                }
                else
                {
                    WriteWebAccessLog(domainId, 3, 1, mailAddress);
                }
                _context.Response.Redirect("~/");
            }
            else
            {
                _context.Response.Redirect("~/Error.aspx?code=22");
            }
        }
    }

    /// <summary>
    /// Logoff.ashx
    /// </summary>
    public class Logoff : LogonBase
    {
        public Logoff(HttpContext context)
            : base(context)
        {
            try
            {
                WebUser.CurrentProfile.Update();
                WriteWebAccessLog(WebUser.CurrentUser.DomainID, 2, WebUser.CurrentUser.MailAddress);

                // 로그인 세션을 제거한다.
                WebUser.ExpireSession();
            }
            catch
            {
            }
            // 사용자를 로그오프시킨다.
            FormsAuthentication.SignOut();
        }

        public void ProcessRequest()
        {
        }
    }
}
