using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections.Generic;
using System.Xml;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using TABS.MailCarrier.WebSDK;
using TABS.MailCarrier.WebSDK.User;

/// <summary>
/// 로그온 사용자 정보를 제공한다.
///  - 데이터베이스 쿼리를 최소화하기 위해 Session에 로그온 사용자 정보를 저장한다.
/// </summary>
public class WebUser
{
    /// <summary>
    /// 로그온 사용자 정보
    ///  사용법
    ///  WebUser.LoginInfo loginInfo = WebUser.CurrentUser;
    ///  Guid userId = loginInfo.DomainUserId;
    /// </summary>
    [Serializable()]
    public class LoginInfo
    {
        private Guid _domainId;           // 도메인 ID
        private Guid _domainUserId;       // 사용자 ID
        private string _userAccount;      // 사용자 메일 계정 (ex:sales)
        private string _name;             // 사용자 이름 (ex:탭스랩)
        private string _mailAddress;      // 사용자 메일 주소 (ex:sales@tabslab.com)
        private string _aliasAddress;     // 사용자 별칭 메일 주소 (ex:sales@tabslab.com)
        private List<string> _aliasAddresses;       // 모든 가능한 별칭 메일 주소 집합(대표 메일 주소 제외)
        private bool _applyPasswordPolicy;                      // 암호 정책 적용 여부
        private bool _noPwdAgeCheck;                            // 암호 만료 기한 검사 안함
        PasswordPolicy.SatisfiedPolicy _meetPasswordPolicy;     // 암호 정책 만족 여부
        private int _pwdAvailableDays;                          // 암호 만료 기한 검사시 암호 잔여일 (-1은 암호 만료 검사 안 함)
        private string _uiLanguage;       // 웹메일 UI 언어 (ko, en)
        private string _timeZoneId;       // 로그인 사용자 타임존 ID(비어 있을 경우 시스템 타임존 사용)
        private TimeZoneInfo _tzi;        // 로그인 사용자 타임존

        public LoginInfo()
        {
            _domainId = Guid.Empty;
            _domainUserId = Guid.Empty;
            _userAccount = "";
            _name = "";
            _mailAddress = _aliasAddress = "";
            _aliasAddresses = null;
            _applyPasswordPolicy = false;
            _noPwdAgeCheck = false;
            _meetPasswordPolicy = PasswordPolicy.SatisfiedPolicy.None;
            _pwdAvailableDays = -1;
            _uiLanguage = "ko";
            _timeZoneId = "";
            _tzi = TimeZoneInfo.Local;
        }

        /// <summary>
        /// 도메인 ID
        /// </summary>
        public Guid DomainID
        {
            get { return _domainId; }
            set { _domainId = value; }
        }

        /// <summary>
        /// 사용자 ID
        /// </summary>
        public Guid DomainUserID
        {
            get { return _domainUserId; }
            set { _domainUserId = value; }
        }

        /// <summary>
        /// 사용자 메일 계정 (ex:sales)
        /// </summary>
        public string UserAccount
        {
            get { return _userAccount; }
            set { _userAccount = value; }
        }

        /// <summary>
        /// 사용자 이름 (ex:탭스랩)
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// 사용자 메일 주소 (ex:sales@tabslab.com)
        /// </summary>
        public string MailAddress
        {
            get { return _mailAddress; }
            set { _mailAddress = value; }
        }

        /// <summary>
        /// 사용자 별칭 메일 주소 (ex:sales@tabslab.com)
        /// </summary>
        public string AliasMailAddress
        {
            get { return _aliasAddress; }
            set { _aliasAddress = value; }
        }

        /// <summary>
        /// 모든 가능한 별칭 메일 주소 집합(대표 메일 주소 제외)
        /// </summary>
        public List<string> AliasMailAddresses
        {
            get { return _aliasAddresses; }
            set { _aliasAddresses = value; }
        }

        /// <summary>
        /// 암호 정책 적용 여부
        /// </summary>
        public bool ApplyPasswordPolicy
        {
            get { return _applyPasswordPolicy; }
            set { _applyPasswordPolicy = value; }
        }

        /// <summary>
        /// 암호 사용 기한 검사 안함 여부
        /// </summary>
        public bool NoPasswordAgeCheck
        {
            get { return _noPwdAgeCheck; }
            set { _noPwdAgeCheck = value; }
        }

        /// <summary>
        /// 암호 정책 만족 여부
        /// </summary>
        public PasswordPolicy.SatisfiedPolicy MeetPasswordPolicy
        {
            get { return _meetPasswordPolicy; }
            set { _meetPasswordPolicy = value; }
        }

        /// <summary>
        /// 암호 만료 기한 검사시 암호 잔여일 (-1은 암호 만료 검사 안 함)
        /// </summary>
        public int PasswordAvailableDays
        {
            get { return _pwdAvailableDays; }
            set { _pwdAvailableDays = value; }
        }

        /// <summary>
        /// UI에 적용될 기본 언어
        /// </summary>
        public string UiLanguage
        {
            get { return _uiLanguage; }
            set { _uiLanguage = value; }
        }

        /// <summary>
        /// 로그인 사용자 타임존 ID(비어 있을 경우 시스템 타임존 사용)
        /// </summary>
        public string TimeZoneId
        {
            get { return _timeZoneId; }
            set 
            { 
                _timeZoneId = value; 
                try
                {
                    _tzi = TimeZoneInfo.FindSystemTimeZoneById(_timeZoneId);
                }
                catch
                {
                    _tzi = TimeZoneInfo.Local;
                }
            }
        }

        public DateTime ToLocalTime(DateTime utc)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(utc, _tzi);
        }

        public DateTime ToUtcTime(DateTime local)
        {
            return TimeZoneInfo.ConvertTimeToUtc(local, _tzi);
        }

        public DateTime GetLocalToday()
        {
            DateTime now = ToLocalTime(DateTime.UtcNow);
            return new DateTime(now.Year, now.Month, now.Day);
        }

        public DateTime GetLocalNow()
        {
            return ToLocalTime(DateTime.UtcNow);
        }

        public DateTime GetSystemToday()
        {
            DateTime now = DateTime.Now;
            return new DateTime(now.Year, now.Month, now.Day);
        }

        public DateTime GetSystemNow()
        {
            return DateTime.Now;
        }
    }

    protected WebUser()
    {
    }

    #region ** Login User Session Management **

    // 로그온한 사용자 정보를 세션에 저장할 때 사용되는 세션 이름
    const string sessionName = "MceWebUserInfo";

    // 로그온한 사용자 프로파일 정보를 세션에 저장할 때 사용되는 세션 이름
    const string profileSessionName = "MceWebUserProfile";

    /// <summary>
    /// 현재 로그온 사용자 정보를 반환한다.
    ///  - 데이터베이스 액세스를 최소화하기 위해 세션에 사용자 정보를 저장한다.
    /// </summary>
    public static LoginInfo CurrentUser
    {
        get
        {
            HttpContext Context = HttpContext.Current;
            if (Context.Session[sessionName] == null)
            {
                LoginInfo loginInfo = new LoginInfo();
                if (Context.User.Identity.Name == "") return loginInfo;
                Guid domainUserId = new Guid(Context.User.Identity.Name);

                DomainUser user = new DomainUser(domainUserId);
                loginInfo.DomainID = user.DomainID;
                loginInfo.DomainUserID = user.DomainUserID;
                loginInfo.UserAccount = user.Account;
                loginInfo.Name = user.Name;
                loginInfo.MailAddress = user.MailAddress;
                loginInfo.AliasMailAddress = user.AliasMailAddress;
                loginInfo.AliasMailAddresses = user.AliasMailAddresses;
                loginInfo.ApplyPasswordPolicy = (user.DomainFlag & TABS.MailCarrier.StgBase.Mcsp.DomainFlag.PasswordPolicy) > 0;
                loginInfo.NoPasswordAgeCheck = (user.StatusFlag & TABS.MailCarrier.StgBase.Mcsp.UserStatusFlag.NoPwdAge) > 0;
                string satisfiedPolicyCode;
                PasswordPolicy pp = new PasswordPolicy();

                if (Context.Session["MceWebUserPassword"] != null)
                {
                    // 로그인 폼을 통해 입력받은 비번이 있을 경우 해당 비번을 평가한다.
                    string passwd = (string)Context.Session["MceWebUserPassword"];
                    loginInfo.MeetPasswordPolicy = pp.Check(user.Account, passwd, user.PasswordSetDate, loginInfo.NoPasswordAgeCheck, out satisfiedPolicyCode);
                    loginInfo.PasswordAvailableDays = pp.PasswordAvailableDays;
                }
                else
                {
                    // 입력 받은 비번이 없을 경우 DB 저장값으로 평가한다.
                    loginInfo.MeetPasswordPolicy =
                        (GlobalConfig.UseOnewayPassword) ?
                        pp.Check4OnewayPassword(user.Account, user.PasswordSetDate, loginInfo.NoPasswordAgeCheck, user.PasswordLength, user.PasswordCharCategoryCount, user.PasswordAccountDupCheck, out satisfiedPolicyCode) :
                        pp.Check(user.Account, user.GetPassword(AppSetting.UseEncryptPassword), user.PasswordSetDate, loginInfo.NoPasswordAgeCheck, out satisfiedPolicyCode);
                    loginInfo.PasswordAvailableDays = pp.PasswordAvailableDays;
                }

                HttpCookie cookie = Context.Request.Cookies["DefaultLanguage"];
                loginInfo.UiLanguage = (cookie != null) ? cookie.Value : "ko";
                cookie = Context.Request.Cookies["DefaultTimeZone"];
                loginInfo.TimeZoneId = (cookie != null) ? cookie.Value : "";

                Context.Session[sessionName] = loginInfo;
                return loginInfo;
            }
            else
            {
                return (LoginInfo)Context.Session[sessionName];
            }
        }
    }

    /// <summary>
    /// 로그온 세션 정보를 제거한다.
    /// </summary>
    public static void ExpireSession()
    {
        HttpContext Context = HttpContext.Current;
        Context.Session.RemoveAll();
    }

    /// <summary>
    /// 현재 로그온 사용자의 프로파일 정보를 반환한다.
    ///  - 데이터베이스 액세스를 최소화하기 위해 세션에 프로파일 정보를 저장한다.
    /// </summary>
    public static UserProfile CurrentProfile
    {
        get
        {
            HttpContext Context = HttpContext.Current;
            if (Context.Session[profileSessionName] == null)
            {
                Guid userId = new Guid(Context.User.Identity.Name);
                UserProfile profileInfo = new UserProfile(userId);
                Context.Session[profileSessionName] = profileInfo;
                return profileInfo;
            }
            else
            {
                return (UserProfile)Context.Session[profileSessionName];
            }
        }
    }

    #endregion
}
