using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Configuration;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Foresight.Data;
using IronIntel.DataModel;
using IronIntel.DataModel.Admin.Customers;
using IronIntel.DataModel.Admin.Users;
using IronIntel.Services;
using Foresight.Services.Log;
using Foresight.Services.Mail;
using IronIntel.DataModel.Admin;
using IronIntel.DataModel.Admin.Machines;

namespace IronIntel.Contractor
{
    /// <summary>
    /// Ironintel contractor站点宿主。目前contractor站点仍然是每个公司一个站点
    /// </summary>
    public class ContractorHost : IIronIntelHost
    {
        public static ContractorHost Instance { get; private set; }

        public static void Init()
        {
            Instance = new ContractorHost();
            IronIntelHostEnvironment.InitHost(Instance);
        }

        private const string APPNAME = "IronIntelCustomerSite";

        private CustomerManager _CustomerManager = null;
        private LoginManager _LoginManager = null;
        private LogWriter _LogWriter = null;
        private SystemParamProvider _MasterSystemParams = null;
        private MachineClassManager _MachineClassManager = null;
        private MachineManager _MachineManager = null;

        public string DataDbConnectionString { get; private set; }
        public string FICDbConnectionString { get; private set; }
        public CustomerInfo Customer { get; private set; }
        
        public DataModel.Contractor.ContractorSystemParams ContractorSystemParams { get; private set; }
        private string AdminDbConnectionString = string.Empty;
        private string MasterDbConnectionString = string.Empty;
        private string MasterDbConnectionString2 = string.Empty;//指向新的数据库服务器

        public string CustomerID { get; private set; }
        private string MasterServiceAddress = string.Empty;
        private string FICSysDbName = string.Empty;

        private string ForesightServiceAppName = string.Empty;
        private string ForesightServiceAddress = string.Empty;
        public string[] RedisServersAddress { get; private set; }

        private ContractorHost()
        {
            SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(ConfigurationManager.AppSettings["DbConntionString"]);
            try
            {
                sb.Password = SystemUtility.DecryptString(sb.Password);
            }
            catch
            {
            }
            DataDbConnectionString = sb.ToString();
            LoadLocalParams();
            InitMasterManager();
            CreateDbObjects();

            _MachineManager = new MachineManager(AdminDbConnectionString);
            _MachineClassManager = new MachineClassManager(AdminDbConnectionString);

            Customer = GetCustomerInfo(CustomerID);
            ContractorSystemParams = new DataModel.Contractor.ContractorSystemParams();
            ContractorSystemParams.Init(Customer, DataDbConnectionString, FICDbConnectionString);
            MasterDbConnectionString2 = _CustomerManager.GetCustomerIronIntelDbConnectionString2(CustomerID);
        }

        private void LoadLocalParams()
        {
            const string PARAM_MASTER_SERVICE_ADDRESS = "MasterServiceAddress";
            const string PARAM_COMPANYID = "CompanyID";
            const string PARAM_FICSYSDB = "FICSysDBName";


            FISqlConnection db = new FISqlConnection(DataDbConnectionString);
            DataTable tb = db.GetDataTableBySQL("select PARAMNAME,PARAMVALUE from SYSPARAMS");
            foreach (DataRow dr in tb.Rows)
            {
                string pname = dr["PARAMNAME"].ToString();
                string pvalue = FIDbAccess.GetFieldString(dr["PARAMVALUE"], string.Empty);
                if (string.Compare(pname, PARAM_COMPANYID, true) == 0)
                {
                    CustomerID = pvalue;
                }
                else if (string.Compare(pname, PARAM_MASTER_SERVICE_ADDRESS, true) == 0)
                {
                    string[] uris = pvalue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    MasterServiceAddress = uris[0];
                }
                else if (string.Compare(pname, PARAM_FICSYSDB, true) == 0)
                {
                    FICSysDbName = pvalue;
                    SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(DataDbConnectionString);
                    sb.InitialCatalog = FICSysDbName;
                    FICDbConnectionString = sb.ConnectionString;
                }
            }
        }

        private void CreateDbObjects()
        {
            try
            {
                IronIntel.Services.Database.Contractor.ContractorDbCreator cd = new Services.Database.Contractor.ContractorDbCreator(DataDbConnectionString);
                cd.Create();

                FI.FIC.Database.FIC.FICDbInitializer ficdb = new FI.FIC.Database.FIC.FICDbInitializer(FICDbConnectionString);
                ficdb.RunIronIntel();
            }
            catch (Exception ex)
            {
                WriteLog(CustomerID, GetType().FullName + ".CreateDbObjects()", "Init db objects failed: " + ex.Message, ex.ToString(), string.Empty);
            }
        }

        private void InitMasterManager()
        {
            IronSysServiceClient client = new IronSysServiceClient(MasterServiceAddress);
            client.AppName = APPNAME;
            AdminDbConnectionString = client.GetAdminDbConnectionString();

            FISqlConnection db = new FISqlConnection(AdminDbConnectionString);
            string masterdb = FIDbAccess.GetFieldString(db.GetRC1BySQL("select PARAMVALUE from SYSPARAMS where PARAMNAME='MASTER_DB_NAME'"), string.Empty);
            SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(AdminDbConnectionString);
            sb.InitialCatalog = masterdb;
            MasterDbConnectionString = sb.ConnectionString;

            _CustomerManager = new CustomerManager(MasterDbConnectionString);
            _LoginManager = new LoginManager(MasterDbConnectionString);
            
            _MasterSystemParams = new SystemParamProvider(MasterDbConnectionString);
           
            ForesightServiceAppName = _MasterSystemParams.ForesightServiceAppName;
            ForesightServiceAddress = _MasterSystemParams.ForesightServiceAddress;

            string str = _MasterSystemParams.RedisServersAddress;
            if(string.IsNullOrWhiteSpace(str))
            {
                RedisServersAddress = new string[0];
            }
            else
            {
                RedisServersAddress = str.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            }
            
            _LogWriter = new LogWriter(ForesightServiceAddress);
            _LogWriter.AppName = ForesightServiceAppName;
        }

        public CustomerManager GetCustomerManager()
        {
            return _CustomerManager;
        }

        public LoginManager GetLoginManager()
        {
            return _LoginManager;
        }

        public long SendEmail(string customerid, MailMessage msg)
        {
            return SendEmail(customerid, APPNAME, msg);
        }

        public long SendEmail(string customerid,string mailtype, MailMessage msg)
        {
            try
            {
                MailSender mail = new MailSender(ForesightServiceAddress);
                mail.AppName = ForesightServiceAppName;
                return mail.SendMail(ForesightServiceAppName, customerid, mailtype, msg);
            }
            catch (Exception ex)
            {
                WriteLog(customerid, "Error", GetType().FullName + ".SendEmail", "Add mail to mailservice failed: " + ex.Message, ex.ToString(), string.Empty);
                throw;
            }
        }

        public void WriteLog(string logtype, string source, string message, string detail, string extmsg)
        {
            _LogWriter.WriteLog(ForesightServiceAppName, CustomerInfo.FORESIGHT, SystemUtility.HostName, APPNAME, logtype, source, message, detail, extmsg);
        }

        public void WriteLog(string customerid, string logtype, string source, string message, string detail, string extmsg)
        {
            _LogWriter.WriteLog(ForesightServiceAppName, customerid, SystemUtility.HostName, APPNAME, logtype, source, message, detail, extmsg);
        }

        public string GetResourceLock(string resourceid, int locksecond)
        {
            return _LogWriter.GetResourceLock(ForesightServiceAppName, resourceid, locksecond);
        }

        public void ReleaseLock(string lockid)
        {
            _LogWriter.ReleaseLock(ForesightServiceAppName, lockid);
        }

        public CustomerInfo GetCustomerInfo(string custid)
        {
            if (Customer != null)
            {
                if (string.Compare(custid, Customer.ID, true) == 0)
                {
                    return Customer;
                }
            }
            return _CustomerManager.GetCustomerByID(custid);
        }

        public DataModel.LicenseInfo GetLicense()
        {
            return _CustomerManager.GetLicense(CustomerID);
        }

        public string GetIronIntelDbConnectionString(string custid)
        {
            if (string.Compare(custid, CustomerID, true) == 0)
            {
                return DataDbConnectionString;
            }
            return _CustomerManager.GetCustomerIronIntelDbConnectionString(custid);
        }

        public T GetContractorManager<T>() where T : DataModel.Contractor.ContractorBusinessBase, new()
        {            
            T rst = new T();
            rst.Init(Customer, DataDbConnectionString, FICDbConnectionString);
            return rst;
        }

        public IronIntel.DataModel.Contractor.Users.UserManager GetUserManager()
        {
            return GetContractorManager<IronIntel.DataModel.Contractor.Users.UserManager>();
        }

        public SystemParamProvider GetSystemParamsProvider()
        {
            return _MasterSystemParams;
        }

        public MachineClassManager GetMachineClassManager()
        {
            return _MachineClassManager;
        }

        public MachineManager GetMachineManager()
        {
            return _MachineManager;
        }
    }
}
