using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Net.Mail;
using System.IO;
using System.Xml;
using Newtonsoft.Json;
using Foresight.Data;
using Foresight.Security.License;
using System.Web;
using System.Runtime.Serialization.Formatters.Binary;
using FI.FIC;
using IronIntel.DataModel.Contractor.Users;
using FI.FIC.Contracts.DataObjects.Enumeration;
using IronIntel.DataModel;
using IronIntel.Contractor.Site;

namespace IronIntel.Contractor.FIC
{
    public class FICHost : IFICHost
    {
        static readonly Guid FIC_MODULE_ID = new Guid("1c6dfe25-347d-4889-ab75-73ade9190d27");
        const string FIC_MODULE_NAME = "Foresight Intelligence Center";
        const string FIC_MODULE_VERSION = "3.0";

        public string FICDbConnectionString
        {
            get
            {
                return ContractorHost.Instance.FICDbConnectionString;
            }
        }

        public string FrsDbConnectionString
        {
            get
            {
                return string.Empty;
            }
        }
        public bool FICInstalled
        {
            get
            {
                return true;
            }
        }

        public bool FRSInstalled
        {
            get
            {
                return false;
            }
        }

        public static void Init()
        {
            FICHostEnvironment.SetHost(new FICHost());
        }

        public byte[] GetCacheData(string key, bool ignoreExpired, ref DateTime createTime)
        {
            byte[] buffer = CacheManager.GetValue(key);
            if (buffer == null)
            {
                return null;
            }
            byte[] tmp = Foresight.Security.SecurityHelper.Decompress(buffer);
            FICCacheObject fc = new FICCacheObject();
            fc.FromBuffer(tmp);
            createTime = fc.CreateTime;
            return fc.Data;
        }

        public DataTable GetCacheDataTable(string key, bool ignoreExpired, ref DateTime createTime)
        {
            byte[] buffer = GetCacheData(key, ignoreExpired, ref createTime);
            if (buffer == null)
            {
                return null;
            }
            //FIDataTable tb = new FIDataTable();
            //tb.FillFromBuffer(buffer);
            //return FIDbAccess.ConvertDataTable(tb);
            return Deserialize(buffer) as DataTable;
        }

        public FICCompanyInfo GetCompanyInfo()
        {
            var cp = ContractorHost.Instance.Customer;
            FICCompanyInfo ficcp = new FICCompanyInfo();
            ficcp.ID = cp.ID;
            ficcp.Name = cp.Name;

            return ficcp;
        }

        public CompanyLic GetLicense()
        {
            var lic = ContractorHost.Instance.GetLicense();
            if (lic == null)
            {
                return null;
            }
            CompanyLic ci = new CompanyLic();
            ci.CompanyID = ContractorHost.Instance.Customer.ID;
            ci.CompanyName = ContractorHost.Instance.Customer.Name;

            Foresight.Security.License.LicenseInfo li = new Foresight.Security.License.LicenseInfo();
            ci.Licenses.Add(li);
            li.CompanyID = ci.CompanyID;
            li.CompanyName = ci.CompanyName;
            li.Expiration = lic.ExpireDate;
            li.ID = Guid.Empty;
            li.StartDate = lic.StartDate;
            li.ModuleID = FIC_MODULE_ID;
            li.ModuleName = FIC_MODULE_NAME;
            li.Version = FIC_MODULE_VERSION;

            foreach (var item in lic.Items)
            {
                var prop = ConvertLicenseItem(item);
                if (prop != null)
                {
                    li.AddtionalPropertes.Add(prop);
                }
            }

            return ci;
        }

        private LicenseAddtionalPropertyObj ConvertLicenseItem(DataModel.LicenseItem item)
        {
            if (item == null)
                return null;
            switch (item.Key)
            {
                case "ColumnLineCombChart":
                    return new LicenseAddtionalPropertyObj { Key = "ColumnLineCombChart", Value = item.Value, Description = item.Description };
                case "ExportChartToXPS":
                    return new LicenseAddtionalPropertyObj { Key = "ExportChartToXPS", Value = item.Value, Description = item.Description };
                case "FreeChart":
                    return new LicenseAddtionalPropertyObj { Key = "FreeChart", Value = item.Value, Description = item.Description };
                case "DrilldownToURL":
                    return new LicenseAddtionalPropertyObj { Key = "DrilldownToURL", Value = item.Value, Description = item.Description };
                case "MaxCharts":
                    return new LicenseAddtionalPropertyObj { Key = "MaxCharts", Value = item.Value, Description = item.Description };
                case "MaxDataTables":
                    return new LicenseAddtionalPropertyObj { Key = "MaxDataTables", Value = item.Value, Description = item.Description };
                case "PrintChart":
                    return new LicenseAddtionalPropertyObj { Key = "PrintChart", Value = item.Value, Description = item.Description };
                case "ScatterChart":
                    return new LicenseAddtionalPropertyObj { Key = "ScatterChart", Value = item.Value, Description = item.Description };
                case "Snapshot":
                    return new LicenseAddtionalPropertyObj { Key = "Snapshot", Value = item.Value, Description = item.Description };
                case "SQLGenerator":
                    return new LicenseAddtionalPropertyObj { Key = "SQLGenerator", Value = item.Value, Description = item.Description };
                    //case "MainStyle":
                    //case "MaxAdminCount":
                    //case "MaxLogins":
                    //case "MaxNormalUerCount":
                    //case "MaxReadOnlyUserCount":
            }
            return null;
        }

        public string GetResourceLock(string resourceid, int locksecond)
        {
           return ContractorHost.Instance.GetResourceLock(resourceid, locksecond);
        }

        private static FICUserInfo ConvertToFICUserInfo(IronIntel.DataModel.Contractor.Users.UserInfo ui)
        {
            var user = new FICUserInfo
            {
                ID = ui.ID,
                IID = ui.UID,
                Enabled = ui.Active,
                DisplayName = ui.Name,
                Mobile = ui.Mobile,
                BusinessPhone = ui.BusinessPhone,
            };
            switch (ui.UserType)
            {
                case UserTypes.Common:
                    user.UserType = FICUserTypes.Common;
                    break;
                case UserTypes.Admin:
                    user.UserType = FICUserTypes.Admin;
                    break;
                case UserTypes.Readonly:
                    user.UserType = FICUserTypes.Readonly;
                    break;
                case UserTypes.SupperAdmin:
                    user.UserType = FICUserTypes.SuperAdmin;
                    break;
                default:
                    user.UserType = FICUserTypes.Readonly;
                    break;
            }
            return user;
        }

        public FICUserInfo GetUserByIID(string useriid)
        {
            var um = ContractorHost.Instance.GetUserManager();
            var ui = um.GetUserByIID(useriid);
            if (ui == null)
            {
                return null;
            }
            return ConvertToFICUserInfo(ui);
        }

        public FICUserInfo GetUserByLoginSessionID(string sessionid)
        {
            var um = ContractorHost.Instance.GetUserManager();
            
            UserInfo ui = um.GetUserByLoginSessionID(sessionid);
            if (ui == null)
            {
                return null;
            }
            return ConvertToFICUserInfo(ui);
        }

        public FICUserInfo GetUserByUserID(string userId)
        {
            var um = ContractorHost.Instance.GetUserManager();

            UserInfo ui = um.GetUserByID(userId);
            if (ui == null)
            {
                return null;
            }
            return ConvertToFICUserInfo(ui);
        }

        public FICUserInfo[] GetUsers()
        {
            var um = ContractorHost.Instance.GetUserManager();
            UserInfo[] users = um.GetSelfUsers();
            List<FICUserInfo> ls = new List<FICUserInfo>(users.Length);
            foreach (UserInfo ui in users)
            {
                ls.Add(ConvertToFICUserInfo(ui));
            }
            return ls.ToArray();
        }

        public string GetUserEmail(string useriid)
        {
            var um = ContractorHost.Instance.GetUserManager();
            UserInfo ui = um.GetUserByIID(useriid);
            if (ui == null)
            {
                return null;
            }
            else
            {
                return ui.ID;
            }
        }

        public void PostMessage(int category, string msg)
        {
            return;
        }

        public void ReleaseResourceLock(string lockid)
        {
            ContractorHost.Instance.ReleaseLock(lockid);
        }

        public void RemoveCache(string key)
        {
            CacheManager.Remove(key);
        }

        public void SendMail(MailMessage message)
        {
            try
            {
                ContractorHost.Instance.SendEmail(ContractorHost.Instance.CustomerID, "FIC", message);
            }
            catch (Exception ex)
            {
                ContractorHost.Instance.WriteLog("Error", this.GetType().FullName + ".SendMail(MailMessage)", "Add fic mail to mail service failed", ex.ToString(), string.Empty);
            }
        }

        public void SetCacheData(string key, byte[] buffer, int expirationsecond, bool slidingExpiration, DateTime createTime)
        {
            if (buffer == null)
            {
                RemoveCache(key);
                return;
            }
            FICCacheObject fc = new FICCacheObject();
            fc.Data = buffer;
            fc.CreateTime = createTime;

            byte[] tmp = Foresight.Security.SecurityHelper.Compress(fc.ToBuffer());
            CacheManager.SetValue(key, tmp, TimeSpan.FromSeconds(expirationsecond));
        }

        public void SetCacheDataTable(string key, DataTable dt, int expirationsecond, bool slidingExpiration, DateTime createTime)
        {
            if (dt == null)
            {
                RemoveCache(key);
            }
            else
            {
                byte[] buffer = Serialize(dt, createTime);
                SetCacheData(key, buffer, expirationsecond, slidingExpiration, createTime);
            }
        }

        public void SubscribeMessage(int category, Action<IEnumerable<MessageInformation>> action)
        {
            return;
        }

        public void WriteLog(string logType, string category, string source, string message, string detail)
        {
            ContractorHost.Instance.WriteLog(logType, source, message, detail,category);
        }

        public List<string> GetUserGroupIDByUserIID(string userIID)
        {
            var grps = ContractorHost.Instance.GetUserManager().GetGroupsByUserIID(userIID);
            List<string> ls = new List<string>(grps.Length);
            foreach(var grp in grps)
            {
                ls.Add(grp.ID);
            }
            return ls;
        }

        public FICUserInfo[] GetUsers(bool hasAdmin)
        {
            if (!hasAdmin)
            {
                return GetUsers();
            }

            var um = ContractorHost.Instance.GetUserManager();

            UserInfo[] localusers = um.GetSelfUsers();
            UserInfo[] foresightusers = um.GetForesightUsers();
            UserInfo[] users = localusers.Union(foresightusers).ToArray();
            List<FICUserInfo> ls = new List<FICUserInfo>(users.Length);
            foreach (UserInfo ui in users)
            {
                ls.Add(ConvertToFICUserInfo(ui));
            }
            return ls.ToArray();
        }

        public LoginContext GetCurrentLoginContext(HttpContext context)
        {
            string session = Site.IronIntelBasePage.GetLoginSessionID(context.Request);
            if (string.IsNullOrWhiteSpace(session))
            {
                return null;
            }

            LoginContext lc = new LoginContext();
            lc.SessionID = session;
            lc.User = GetUserByLoginSessionID(session);
            lc.LanguageID = GetLgID(context);
            return lc;
        }

        private string GetLgID(HttpContext context)
        {
            var language = context.Request.Cookies[IronIntelBasePage.LANGUAGECOOKIENAME];
            if (language != null)
            {
                return language.Value;
            }
            return ResLanguage.ClientCurrentLanguage;
        }

        public string ProductEdition
        {
            get
            {
                return "General";
            }
        }

        public string FIExternalDBConnectionString
        {
            get
            {
                return string.Empty;
            }
        }

        public SpecialDatabaseConnectionInfo[] GetSpecialDatabaseConnections()
        {
            throw new NotImplementedException();
        }

        public string GetStyleDefines(string useriid)
        {
            throw new NotImplementedException();
            //StringBuilder s = new StringBuilder();
            //s.Append(@"<?xml version=""1.0"" encoding=""UTF-8""?>");
            //s.Append("<root>");
            //s.Append("<Workspace><Title><Background>#ff00ff</Background><Foreground>#222222</Foreground></Title></Workspace>");
            //s.Append("<Chart><Title><Background>#333333</Background><Foreground>#444444</Foreground></Title><Board>#555555</Board></Chart>");
            //s.Append("<Board><Title><Background>#666666</Background><Foreground>#777777</Foreground></Title></Board>");
            //s.Append("</root>");
            //return s.ToString();
         ////   Services.CustUIStyle uistyle = SystemParams.GetUIStyle(useriid);

         //   StringBuilder s = new StringBuilder();
         //   s.Append(@"<?xml version=""1.0"" encoding=""UTF-8""?>");
         //   s.Append("<root>");
         //   s.Append("<Workspace><Title><Background></Background><Foreground>#000000</Foreground></Title></Workspace>");
         //   s.Append("<Chart><Title><Background>" + uistyle.ChartTitleBackgroundColor + "</Background><Foreground></Foreground></Title><Board>" + uistyle.ChartBorderColor + "</Board></Chart>");
         //   //s.Append("<Board><Title><Background>#666666</Background><Foreground>#777777</Foreground></Title></Board>");
         //   s.Append("</root>");
         //   return s.ToString();
        }
        public Dictionary<string, string> GetAdditionalParameter()
        {            
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("ConnectorToken", ContractorHost.Instance.ContractorSystemParams.GetFICStringParam("ConnectorToken"));
            dic.Add("ConnectorServer", ContractorHost.Instance.ContractorSystemParams.GetFICStringParam("ConnectorServer"));
            dic.Add("LdapAgentID", ContractorHost.Instance.ContractorSystemParams.GetFICStringParam("LdapAgentID"));
            dic.Add("LdapAgentToken", ContractorHost.Instance.ContractorSystemParams.GetFICStringParam("LdapAgentToken"));
            dic.Add("CanUseConnectorLDAP", ContractorHost.Instance.ContractorSystemParams.GetFICStringParam("CanUseConnectorLDAP"));

            return dic;
        }

        public FICUserInfo[] GetSimpleUsers(bool hasAdmin)
        {
            var users = GetUsers(hasAdmin);
            List<FICUserInfo> ls = new List<FICUserInfo>();
            foreach (var user in users)
            {
                var us = new FICUserInfo();
                us.IID = user.IID;
                us.ID = user.ID;
                us.DisplayName = user.DisplayName;
                ls.Add(us);
            }
            return ls.ToArray();
        }

        class FICCacheObject
        {
            public byte[] Data = null;
            public DateTime CreateTime = DateTime.Now;

            public byte[] ToBuffer()
            {
                byte[] rst = new byte[Data.Length + 8];
                byte[] bf1 = BitConverter.GetBytes(CreateTime.Ticks);
                Buffer.BlockCopy(bf1, 0, rst, 0, 8);
                Buffer.BlockCopy(Data, 0, rst, 8, Data.Length);

                return rst;
            }

            public void FromBuffer(byte[] buffer)
            {
                long l = BitConverter.ToInt64(buffer, 0);
                CreateTime = new DateTime(l);
                Data = new byte[buffer.Length - 8];
                Buffer.BlockCopy(buffer, 8, Data, 0, buffer.Length - 8);
            }
        }

        #region - (De)Serialize -

        private static byte[] Serialize(object obj, DateTime createtime)
        {
            if (obj == null)
            {
                return null;
            }
            var cacheObj = new RedisCacheObject
            {
                CreateTime = createtime,
                Data = obj
            };
            byte[] data;
            using (var ms = new MemoryStream())
            {                
                new BinaryFormatter().Serialize(ms, cacheObj);
                data = ms.ToArray();
            }
            return data;
        }

        private static object Deserialize(byte[] buffer)
        {
            using (var ms = new MemoryStream(buffer, false))
            {
                return new BinaryFormatter().Deserialize(ms);
            }
        }

        

        #endregion


        [Serializable]
        class RedisCacheObject
        {
            public DateTime CreateTime { get; set; }
            public object Data { get; set; }
        }

    }

}