using FI.FIC.Contracts.DataObjects.BLObject;
using FI.FIC.Models;
using IronIntel.Contractor.Users;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace IronIntel.Contractor.Site.Security
{
    public class FilterBasePage : ContractorBasePage
    {
        private const string sqlIn = "In";
        private const string isnull = "Is Null";
        private const string isnotnull = "Is Not Null";
        private const string defaultLanageCode = "en-us";
        protected void ProcessRequest(string methodName)
        {
            object result = null;

            try
            {
                if (methodName != null)
                {
                    switch (methodName.ToUpper())
                    {
                        case "GETFILTEROBJECT":
                            result = GetFilterObject();
                            break;
                        case "SAVEFILTER":
                            result = SaveFilter();
                            break;
                        case "GETDATASOURCE":
                            result = GetDataSource();
                            break;
                        case "GETTABLEFILTERS":
                            result = GetTableFilters();
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                result = ex.Message;
                SystemParams.WriteLog("Error", "FilterBasePage.ProcessRequest", ex.Message, ex.ToString());
            }

            string json = JsonConvert.SerializeObject(result);
            Response.Write(json);
            Response.End();
        }

        protected override bool AllowCurrentLoginSessionEnter()
        {
            var f = base.AllowCurrentLoginSessionEnter();
            if (!f)
            {
                return false;
            }

            // check whether you are admin.
            var session = GetCurrentLoginSession();
            if (session == null || session.User == null)
            {
                return false;
            }
            var ui = UserManagement.GetUserByIID(session.User.UID);
            return ui != null && ui.UserType >= UserTypes.Admin;
        }

        protected override bool ThrowIfNotAllowed { get { return true; } }

        private FilterObject GetFilterObject()
        {
            var p = Request.Form["ClientData"];
            p = HttpUtility.HtmlDecode(p);
            int index = p.IndexOf(";");
            string iid = p.Substring(0, index);
            string type = p.Substring(index + 1);//1为Group 2为User

            GlobalFilterAuthorize[] globalFilters = null;
            List<DataTableInfo> tableList = null;
            TableFilterAuthorize[] tableFilters = null;
            List<FI.FIC.Contracts.DataObjects.BaseObject.Plugin> pluginList = PluginManager.GetPlugin();
            if (type == "1")
            {
                globalFilters = GlobalFilterManager.GetGlobalFilterAuthorizeForGroup(iid);
                tableList = DataTableManager.GetHaveTableFilterDataTableListForUserGroup(iid, defaultLanageCode);
                if (tableList != null && tableList.Count > 0)
                {
                    tableFilters = GlobalFilterManager.GetTableFilterAuthorizeForGroup(iid, tableList[0].IID);
                }
            }
            else if (type == "2")
            {
                globalFilters = GlobalFilterManager.GetGlobalFilterAuthorizeForUser(iid);
                tableList = DataTableManager.GetHaveTableFilterDataTableList(iid, defaultLanageCode);
                if (tableList != null && tableList.Count > 0)
                {
                    tableFilters = GlobalFilterManager.GetTableFilterAuthorizeForUser(iid, tableList[0].IID);
                }
            }

            FilterObject filterObj = new FilterObject();

            if (globalFilters != null)
            {
                List<Filter> gfs = new List<Filter>();
                foreach (var item in globalFilters)
                {
                    Filter gf = new Filter();
                    gf.FilterName = item.FilterName;
                    gf.FilterCondition = item.FilterCondition ?? " ";
                    gf.FilterDataType = (int)item.FilterDataType;
                    gf.FilterType = (int)item.FilterType;
                    if (gf.FilterType == 0)
                        gf.FilterTypeString = "Single Value";
                    else
                        gf.FilterTypeString = getPluginName(item.PluginID, pluginList);
                    gf.FilterValue = item.FilterValue;
                    gf.IID = item.IID;
                    gf.PluginID = item.PluginID;

                    gfs.Add(gf);
                }
                filterObj.GlobalFilters = gfs.ToArray();
            }

            if (tableList != null)
            {
                List<KeyValuePair<string, string>> dts = new List<KeyValuePair<string, string>>();
                foreach (var item in tableList)
                {
                    KeyValuePair<string, string> kv = new KeyValuePair<string, string>(item.IID, item.DataTableName);
                    dts.Add(kv);
                }
                filterObj.DataTableList = dts.ToArray();
            }

            if (tableFilters != null)
            {
                List<Filter> tfs = new List<Filter>();
                foreach (var item in tableFilters)
                {
                    Filter tf = new Filter();
                    tf.FieldName = item.FieldName;
                    tf.FilterName = item.FilterName;
                    tf.FilterCondition = item.FilterCondition ?? " ";
                    tf.FilterDataType = (int)item.FilterDataType;
                    tf.FilterType = (int)item.FilterType;
                    if (tf.FilterType == 0)
                        tf.FilterTypeString = "Single Value";
                    else
                        tf.FilterTypeString = getPluginName(item.PluginID, pluginList);
                    tf.FilterValue = item.FilterValue;
                    tf.IID = item.IID;
                    tf.PluginID = item.PluginID;

                    tfs.Add(tf);
                }
                filterObj.FirstTableFilters = tfs.ToArray();
            }

            return filterObj;
        }

        private string getPluginName(string iid, List<FI.FIC.Contracts.DataObjects.BaseObject.Plugin> pluginList)
        {
            string result = "";
            if (pluginList != null)
            {
                var plugin = pluginList.FirstOrDefault((p) => p.IID.Equals(iid, StringComparison.OrdinalIgnoreCase));
                if (plugin != null)
                    result = plugin.PluginName;
            }
            return result;
        }

        private object SaveFilter()
        {
            if (GetCurrentLoginSession() != null)
            {
                var s = Request.Form["ClientData"];
                s = HttpUtility.HtmlDecode(s);
                SaveFilterObject item = JsonConvert.DeserializeObject<SaveFilterObject>(s);

                if (item.Type == 2)
                {
                    var user = UserManagement.GetUserByIID(item.UserIID);
                    if (user.UserType == UserTypes.Admin)//Admin用户不需要修改
                        return "\"OK\"";
                }
                string error = "";
                if (!Validate(ref error, item))
                {
                    return new ErrorObject() { ErrorCode = 1, ErrorMessage = error };
                }
                DoSaveFilter(item);
                return "\"OK\"";
            }
            else
            {
                return "\"Failed\"";
            }
        }

        private void DoSaveFilter(SaveFilterObject filterObject)
        {
            List<GlobalFilterAuthorize> globalFilter = new List<GlobalFilterAuthorize>();
            if (filterObject.GlobalFilter != null)
            {
                foreach (var item in filterObject.GlobalFilter)
                {
                    GlobalFilterAuthorize gf = new GlobalFilterAuthorize();
                    gf.FilterName = item.FilterName;
                    gf.FilterCondition = item.FilterCondition;
                    gf.FilterDataType = (FI.FIC.Contracts.DataObjects.Enumeration.DBDataType)item.FilterDataType;
                    gf.FilterType = (FI.FIC.Contracts.DataObjects.Enumeration.FilterType)item.FilterType;
                    gf.FilterValue = item.FilterValue;
                    gf.IID = item.IID;
                    gf.PluginID = item.PluginID;

                    globalFilter.Add(gf);
                }
            }

            List<TableFilterAuthorize> tableFilter = new List<TableFilterAuthorize>();
            if (filterObject.TableFilters != null)
            {
                foreach (var tfobj in filterObject.TableFilters)
                {
                    foreach (var item in tfobj.Filters)
                    {
                        TableFilterAuthorize tf = new TableFilterAuthorize();
                        tf.FilterName = item.FilterName;
                        tf.FilterCondition = item.FilterCondition;
                        tf.FilterDataType = (FI.FIC.Contracts.DataObjects.Enumeration.DBDataType)item.FilterDataType;
                        tf.FilterType = (FI.FIC.Contracts.DataObjects.Enumeration.FilterType)item.FilterType;
                        tf.FilterValue = item.FilterValue;
                        tf.IID = item.IID;
                        tf.PluginID = item.PluginID;

                        tableFilter.Add(tf);
                    }
                }
            }

            if (filterObject.Type == 1)//1为Group，2为User
            {
                GlobalFilterManager.SaveGlobalFilterAuthorizeForGroup(filterObject.UserIID, globalFilter.ToArray(), tableFilter.ToArray());
            }
            else if (filterObject.Type == 2)
            {
                GlobalFilterManager.SaveGlobalFilterAuthorizeForUser(filterObject.UserIID, globalFilter.ToArray(), tableFilter.ToArray());
            }
        }

        private DataSourceObject GetDataSource()
        {
            DataSourceObject result = new DataSourceObject();
            var s = Request.Form["ClientData"];
            string dsiid = HttpUtility.HtmlDecode(s);
            PluginStructure dsStructure = PluginManager.GetPluginStructure(dsiid);
            PluginManager pm = new PluginManager();
            DataTable dt = pm.GetSourceData(dsiid, null);

            int indexOfName = dt.Columns.IndexOf(dsStructure.DataImport.DisplayField);
            int indexOfID = dt.Columns.IndexOf(dsStructure.DataImport.ValueField);
            int indexOfPID = dt.Columns.IndexOf(dsStructure.DataImport.ParentField);
            if (indexOfName < 0)
                indexOfName = dt.Columns.IndexOf("Name");
            if (indexOfID < 0)
                indexOfID = dt.Columns.IndexOf("ID");
            if (indexOfPID < 0)
                indexOfPID = dt.Columns.IndexOf("PID");

            result.IID = dsStructure.IID;
            result.IsFlat = dsStructure.IsFlat == 1;
            if (!result.IsFlat)
                result.IsFlat = IsFlat(dt, indexOfPID);
            result.Name = dsStructure.PluginName;
            result.DisplayField = dsStructure.DataImport.DisplayField;
            result.ValueField = dsStructure.DataImport.ValueField;

            List<DataSourceData> datas = new List<DataSourceData>();
            if (result.IsFlat)
            {
                foreach (DataRow dr in dt.Select("", dt.Columns[indexOfID].ColumnName + " asc"))
                {
                    DataSourceData ds = new DataSourceData();
                    ds.ID = dr[indexOfID].ToString();
                    ds.Description = dr[indexOfName].ToString();
                    if (indexOfPID >= 0)
                        ds.PID = dr[indexOfPID].ToString();
                    datas.Add(ds);
                }
                //datas = datas.OrderBy((d) => d.ID).ToList();
            }
            else
            {
                Dictionary<string, DataSourceData> nodes = new Dictionary<string, DataSourceData>();
                foreach (DataRow dr in dt.Select("", dt.Columns[indexOfID].ColumnName + " asc"))
                {
                    DataSourceData ds = new DataSourceData();
                    ds.ID = dr[indexOfID].ToString();
                    ds.Description = dr[indexOfName].ToString();
                    if (indexOfPID >= 0)
                        ds.PID = dr[indexOfPID].ToString();
                    //if (nodes.ContainsKey(ds.PID))
                    //{
                    //    DataSourceData pnode = nodes[ds.PID];
                    //    List<DataSourceData> subNodes = new List<DataSourceData>();
                    //    if (pnode.SubData != null)
                    //        subNodes.AddRange(pnode.SubData);
                    //    subNodes.Add(ds);
                    //    pnode.SubData = subNodes.ToArray();
                    //}
                    nodes[ds.ID] = ds;
                }

                foreach (var kv in nodes)
                {
                    if (nodes.ContainsKey(kv.Value.PID))
                    {
                        DataSourceData pnode = nodes[kv.Value.PID];
                        List<DataSourceData> subNodes = new List<DataSourceData>();
                        if (pnode.SubData != null)
                            subNodes.AddRange(pnode.SubData);
                        subNodes.Add(kv.Value);
                        pnode.SubData = subNodes.ToArray();
                    }
                    else
                        datas.Add(kv.Value);
                }
            }
            result.Data = datas.ToArray();

            return result;
        }

        private Filter[] GetTableFilters()
        {
            var p = Request.Form["ClientData"];
            p = HttpUtility.HtmlDecode(p);
            int index = p.IndexOf(";");
            string iid = p.Substring(0, index);
            int index1 = p.IndexOf(";", index + 1);
            string type = p.Substring(index + 1, index1 - index - 1);//1为Group 2为User
            string dtiid = p.Substring(index1 + 1);

            TableFilterAuthorize[] tableFilters = null;
            List<FI.FIC.Contracts.DataObjects.BaseObject.Plugin> pluginList = PluginManager.GetPlugin();
            if (type == "1")
            {
                tableFilters = GlobalFilterManager.GetTableFilterAuthorizeForGroup(iid, dtiid);
            }
            else if (type == "2")
            {
                tableFilters = GlobalFilterManager.GetTableFilterAuthorizeForUser(iid, dtiid);
            }

            List<Filter> filters = new List<Filter>();

            if (tableFilters != null)
            {
                foreach (var item in tableFilters)
                {
                    Filter tf = new Filter();
                    tf.FieldName = item.FieldName;
                    tf.FilterName = item.FilterName;
                    tf.FilterCondition = item.FilterCondition ?? " ";
                    tf.FilterDataType = (int)item.FilterDataType;
                    tf.FilterType = (int)item.FilterType;
                    if (tf.FilterType == 0)
                        tf.FilterTypeString = "Single Value";
                    else
                        tf.FilterTypeString = getPluginName(item.PluginID, pluginList);
                    tf.FilterValue = item.FilterValue;
                    tf.IID = item.IID;
                    tf.PluginID = item.PluginID;

                    filters.Add(tf);
                }
            }
            return filters.ToArray();
        }

        /// <summary>
        /// 判断数据源的数据是否是树形结构
        /// </summary>
        /// <returns></returns>
        private bool IsFlat(DataTable dt, int pidIndex)
        {
            if (pidIndex < 0) return true;

            List<string> ids = new List<string>();
            List<string> pids = new List<string>();

            foreach (DataRow dr in dt.Rows)
            {
                string id = dr[pidIndex].ToString();
                if (pids.IndexOf(id) >= 0)
                    return false;

                string pid = dr[pidIndex].ToString();
                if (ids.IndexOf(pid) >= 0)
                    return false;

                ids.Add(id);
                pids.Add(pid);
            }
            return true;
        }

        private bool Validate(ref string error, SaveFilterObject FilterObj)
        {
            string msg = "";
            if (FilterObj.GlobalFilter != null && FilterObj.GlobalFilter.Length > 0)
            {
                Filter errorObj = null;
                if (!ValidateFilter(ref msg, FilterObj.GlobalFilter, out errorObj))
                {
                    //string TableFilterError = CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A016") + "\n";
                    error = "Filter '{0}' in global filter:" + "\n";
                    error = string.Format(error, errorObj.FilterName);
                    error = error + msg;
                    return false;
                }
            }
            if (FilterObj.TableFilters != null && FilterObj.TableFilters.Length > 0)
            {
                foreach (var tf in FilterObj.TableFilters)
                {
                    Filter errorObj = null;
                    if (!ValidateFilter(ref msg, tf.Filters, out errorObj))
                    {
                        //string TableFilterError = CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A017") + "\n";
                        error = "Filter '{0}' in  the data Table '{1}':" + "\n";
                        error = string.Format(error, errorObj.FilterName, tf.TableName);
                        error = error + msg;
                        return false;
                    }

                }
            }
            return true;
        }

        private bool ValidateFilter(ref string error, Filter[] Filters, out Filter errorObj)
        {
            errorObj = null;
            for (int i = 0; i < Filters.Length; i++)
            {
                Filter item = Filters[i];
                if (!string.IsNullOrWhiteSpace(item.FilterCondition))
                {
                    if ((item.FilterCondition == isnull) || (item.FilterCondition == isnotnull))
                    {
                        item.FilterValue = "";
                    }
                    else if (item.FilterCondition != sqlIn)
                    {
                        bool returnValue = true;
                        switch (item.FilterDataType)
                        {
                            case (int)FI.FIC.Contracts.DataObjects.Enumeration.DBDataType.dtBoolean:
                                try
                                {
                                    bool.Parse(item.FilterValue);
                                }
                                catch
                                {
                                    error = "The Filter value must be True/False.";// CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A012");
                                    returnValue = false;
                                }
                                break;
                            case (int)FI.FIC.Contracts.DataObjects.Enumeration.DBDataType.dtDate:
                                try
                                {
                                    //必须要满足(月日年)或(年月日)的格式
                                    DateTime t = DateTime.Now;
                                    try
                                    {
                                        t = DateTime.Parse(item.FilterValue, new System.Globalization.DateTimeFormatInfo());
                                    }
                                    catch
                                    {
                                    }
                                    string tFilterValue = item.FilterValue.Replace(".", "-").Replace("/", "-");
                                    if (!tFilterValue.StartsWith(t.ToString("MM-dd-yyyy"))
                                        && !tFilterValue.StartsWith(t.ToString("MM-d-yyyy"))
                                        && !tFilterValue.StartsWith(t.ToString("M-dd-yyyy"))
                                        && !tFilterValue.StartsWith(t.ToString("M-d-yyyy"))
                                        && !tFilterValue.StartsWith(t.ToString("yyyy-MM-dd"))
                                        && !tFilterValue.StartsWith(t.ToString("yyyy-MM-d"))
                                        && !tFilterValue.StartsWith(t.ToString("yyyy-M-dd"))
                                        && !tFilterValue.StartsWith(t.ToString("yyyy-M-d")))
                                    {
                                        throw new Exception();
                                    }
                                }
                                catch
                                {
                                    error = "The Filter value must be a date.";// CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A013");
                                    error += " " + "Date format must be 'MM/dd/yyyy' or 'yyyy-MM-dd'";// CommonHelper.GetLangauge("LHBIS.FIC.Client.Wizard.ChartWizardHelper.A286");
                                    returnValue = false;
                                }
                                break;
                            case (int)FI.FIC.Contracts.DataObjects.Enumeration.DBDataType.dtFloat:
                                try
                                {
                                    float.Parse(item.FilterValue);
                                }
                                catch
                                {
                                    error = "The Filter value must be a floating point.";//CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A014");
                                    returnValue = false;
                                }
                                break;
                            case (int)FI.FIC.Contracts.DataObjects.Enumeration.DBDataType.dtInteger:
                                try
                                {
                                    int.Parse(item.FilterValue);
                                }
                                catch
                                {
                                    error = "The Filter Value must be an integer.";// CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A015");
                                    returnValue = false;
                                }
                                break;
                            case (int)FI.FIC.Contracts.DataObjects.Enumeration.DBDataType.dtGuid:
                                try
                                {
                                    if (string.IsNullOrEmpty(item.FilterValue))
                                        item.FilterValue = Guid.Empty.ToString();
                                    else
                                        new Guid(item.FilterValue);
                                }
                                catch
                                {
                                    error = "The Filter Value must be a GUID.";// CommonHelper.GetLangauge("LHBIS.FIC.Client.Modules.FilterManagement.A018");
                                    returnValue = false;
                                }
                                break;
                        }

                        if (returnValue == false)
                        {
                            errorObj = item;
                            return returnValue;
                        }
                    }

                    if (item.FilterValue.Length > 2000)
                    {
                        errorObj = item;
                        error = "The length of the Filter Value must be less than 2000.";// 没有资源号
                        return false;
                    }
                }
            }
            return true;
        }

        #region Model
        public class Filter
        {
            public string IID { get; set; }
            public string FilterName { get; set; }
            public int FilterType { get; set; }
            public string FilterTypeString { get; set; }
            public string FieldName { get; set; }
            public int FilterDataType { get; set; }
            public string FilterDataTypeString
            {
                get
                {
                    string dataType = Enum.GetName(typeof(FI.FIC.Contracts.DataObjects.Enumeration.DBDataType), FilterDataType);
                    if (dataType == null) return null;
                    if (dataType.StartsWith("dt"))
                    {
                        return dataType.Substring(2, dataType.Length - 2);
                    }
                    return dataType;
                }
            }
            public string FilterCondition { get; set; }
            public string FilterValue { get; set; }
            public string PluginID { get; set; }
        }

        /// <summary>
        /// 包含Global Filter, DataTable List和第一个DataTable的Filter
        /// </summary>
        public class FilterObject
        {
            public Filter[] GlobalFilters { get; set; }

            public KeyValuePair<string, string>[] DataTableList { get; set; }//IID/Name

            public Filter[] FirstTableFilters { get; set; }//第一个DataTable的Filter
        }

        public class TableFilterObject
        {
            public string TableIID { get; set; }
            public string TableName { get; set; }
            public Filter[] Filters { get; set; }
        }

        public class SaveFilterObject
        {
            public string UserIID { get; set; }//用户或用户组的IID
            public int Type { get; set; }//1
            public Filter[] GlobalFilter { get; set; }
            public TableFilterObject[] TableFilters { get; set; }
        }
        public class DataSourceObject
        {
            public string IID { get; set; }
            public string Name { get; set; }
            public bool IsFlat { get; set; }

            public string DisplayField { get; set; }
            public string ValueField { get; set; }


            public DataSourceData[] Data { get; set; }
        }

        public class DataSourceData
        {
            public string ID { get; set; }
            public string PID { get; set; }
            public string Description { get; set; }
            public DataSourceData[] SubData { get; set; }
        }

        public class ErrorObject
        {
            public int ErrorCode { get; set; }
            public string ErrorMessage { get; set; }
        }

        #endregion
    }
}
