using log4net;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Storage;

namespace VIZ.Package.Service
{
    /// <summary>
    /// VIZ命令ControlObject服务
    /// </summary>
    public partial class VizCommandControlObjectService
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(VizCommandControlObjectService));

        /// <summary>
        /// 不启用编辑类型
        /// </summary>
        /// <remarks>
        /// 不启用编辑则可以直接在GridControl的单元格中直径进行值修改
        /// </remarks>
        public static readonly List<VizControlFieldType> ALLOW_EDITING_FALSE_TYPES = new List<VizControlFieldType>
        {
             VizControlFieldType.none,
             VizControlFieldType.boolean,
             VizControlFieldType.image,
             VizControlFieldType.duplet,
             VizControlFieldType.triplet,
             VizControlFieldType.font
        };

        // =======================================================================
        // public Function
        // =======================================================================

        /// <summary>
        /// 获取控制对象List列定义
        /// </summary>
        /// <param name="schema">定义信息</param>
        /// <returns>列定义</returns>
        public List<GridColumnControlFieldDefinition> GetControlObjectListColumn(string schema)
        {
            List<GridColumnControlFieldDefinition> columns = new List<GridColumnControlFieldDefinition>();

            using (System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(schema)))
            {
                XElement element = XElement.Load(ms);
                XElement elementSchema = element.Element("schema");
                if (elementSchema == null)
                    return columns;

                ControlObject_Schema_Node schemaNode = new ControlObject_Schema_Node();
                schemaNode.FromXmlElement(elementSchema);

                foreach (ControlObject_Field_node field in schemaNode.Fields)
                {
                    GridColumnControlFieldDefinition column = new GridColumnControlFieldDefinition();
                    column.Header = (field.Name == field.Description) ? field.Name : $"({field.Description}){field.Name}";
                    column.FieldName = field.Name;
                    column.Type = this.GetControlFieldType(field.Type);
                    column.AllowEditing = !ALLOW_EDITING_FALSE_TYPES.Contains(column.Type);

                    columns.Add(column);
                }
            }

            return columns;
        }

        /// <summary>
        /// 获取控制对象List数据
        /// </summary>
        /// <param name="xml">数据</param>
        /// <returns>数据</returns>
        public List<ExpandoObject> GetControlObjectListData(string xml)
        {
            List<ExpandoObject> items = new List<ExpandoObject>();
            if (string.IsNullOrWhiteSpace(xml))
                return items;

            try
            {
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml)))
                {
                    XElement element = XElement.Load(ms);

                    ControlObject_Entry_Node root = new ControlObject_Entry_Node();
                    root.FromXmlElement(element);

                    foreach (var row in root.Elements)
                    {
                        IDictionary<string, object> obj = new ExpandoObject();
                        ControlObject_Entry_Node data = row.Entrys.FirstOrDefault(p => p.Name == "data");
                        if (data == null)
                            continue;

                        foreach (var cell in data.Entrys)
                        {
                            obj[cell.Name] = cell.Value;
                        }

                        items.Add(obj as ExpandoObject);
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }

            return items;
        }

        /// <summary>
        /// 获取控制对象XML数据
        /// </summary>
        /// <param name="items">控制对象数据</param>
        /// <returns>XML数据</returns>
        public string GetControlObjectXml(List<ExpandoObject> items)
        {
            ControlObject_Entry_Node root = new ControlObject_Entry_Node();
            foreach (IDictionary<string, object> row in items)
            {
                ControlObject_Element_Node element = new ControlObject_Element_Node();
                ControlObject_Entry_Node data = new ControlObject_Entry_Node();
                data.Name = "data";
                foreach (var kv in row)
                {
                    ControlObject_Entry_Node cell = new ControlObject_Entry_Node();
                    cell.Name = kv.Key;
                    cell.Value = kv.Value == null ? string.Empty : kv.Value.ToString();
                    data.Entrys.Add(cell);
                }
                element.Entrys.Add(data);
                root.Elements.Add(element);
            }

            XElement root_element = root.ToXmlElement();

            return $"<?xml version=\"1.0\"?>{root_element.ToString(SaveOptions.DisableFormatting)}";
        }

        /// <summary>
        /// 获取场景树节点信息
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">Viz场景</param>
        /// <returns>场景树节点信息</returns>
        public List<VizTreeNodeInfo> GetTreeNodeList(ConnModel conn, VizScene scene)
        {
            List<VizTreeNodeInfo> list = new List<VizTreeNodeInfo>();

            string cmd = $"{scene}*TREE GET";
            string result = conn.EndpointManager.Request(cmd);
            List<string> nodes = result.Split('{').Select(p => p.Replace("}", "")).ToList();

            foreach (string node in nodes)
            {
                if (string.IsNullOrWhiteSpace(node))
                    continue;

                // 1 29073 object 1
                string[] pars = node.Split(' ');

                VizTreeNodeInfo info = new VizTreeNodeInfo();
                info.Path = pars[0];
                info.Num = pars[1];
                info.Name = pars[2];
                // pars[3] 有的节点有，有的节点没有

                list.Add(info);
            }

            return list;
        }

        /// <summary>
        /// 获取控制对象ID集合
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">Viz场景层</param>
        /// <returns>控制对象ID集合</returns>
        public List<string> GetControlObjectIds(ConnModel conn, VizScene scene)
        {
            string cmd = $"{scene}*TREE SEARCH_FOR_CONTAINER_WITH_PROPERTY BUILT_IN*FUNCTION BUILT_IN*FUNCTION*ControlObject";
            string result = conn.EndpointManager.Request(cmd);
            string[] source = result.Trim().Split(' ');

            return source.ToList();
        }

        /// <summary>
        /// 获取控制对象信息
        /// </summary>
        /// <param name="conn">连接</param>
        /// <returns>控制对象列表</returns>
        public ControlObjectModel GetControlObject(ConnModel conn)
        {
            ControlObjectModel obj = new ControlObjectModel();

            // Step 1. 获取场景树信息
            List<VizTreeNodeInfo> treeNodeList = this.GetTreeNodeList(conn, VizScene.MAIN_SCENE);
            Dictionary<string, VizTreeNodeInfo> treeNodeDic = treeNodeList.ToDictionary(p => $"#{p.Num}", p => p);

            // Step 2. 获取控制对象ID集合
            List<string> ids = this.GetControlObjectIds(conn, VizScene.MAIN_SCENE);

            // Step 3. 获取控制对象信息, 只获取第一个控制对象
            string id = ids.FirstOrDefault();
            if (string.IsNullOrWhiteSpace(id))
                return obj;

            if (!treeNodeDic.TryGetValue(id, out VizTreeNodeInfo objTreeNodeInfo))
                return obj;

            // Step 4. 获取第一个控制对象的信息
            obj.TreeNodePath = objTreeNodeInfo.Path;
            obj.TreeNodeName = objTreeNodeInfo.Name;
            obj.Description = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.description);
            obj.UseAllDirectors = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.use_all_directors) == "1";
            // 切换场景
            obj.TransitionLogic = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.trio_loadable) == "1";
            obj.LayerIdentifier = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.layer);
            obj.StateIdentifier = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.state);
            obj.BackgroundScene = this.GetControlObjectParameter(conn, VizScene.MAIN_SCENE, obj.TreeNodePath, VizControlObjectParameters.background);

            // Step 5. 获取第一个控制对象的字段描述
            string fieldDetails = this.GetControlObjectResult(conn, VizScene.MAIN_SCENE, obj.TreeNodePath);
            obj.FieldDetails = fieldDetails ?? string.Empty;

            // Step 6. 更新控制对象字段
            this.UpdateControlObjectField(conn, obj, obj.FieldDetails, true);

            return obj;
        }

        /// <summary>
        /// 更新控制对象模型
        /// </summary>
        /// <param name="model">模型</param>
        /// <param name="entity">实体</param>
        public void UpdateControlObjectModel(ControlObjectModel model, ControlObjectEntity entity)
        {
            // Step 1. 获取第一个控制对象的信息
            model.TreeNodePath = entity.TreeNodePath;
            model.TreeNodeName = entity.TreeNodeName;
            model.Description = entity.Description;
            model.FieldDetails = entity.FieldDetails ?? string.Empty;
            model.CustomFieldDetails = entity.CustomFieldDetails ?? string.Empty;
            model.UseAllDirectors = entity.UseAllDirectors;
            model.TransitionLogic = entity.TransitionLogic;
            model.LayerIdentifier = entity.LayerIdentifier;
            model.StateIdentifier = entity.StateIdentifier;
            model.BackgroundScene = entity.BackgroundScene;

            this.UpdateControlObjectField(null, model, model.FieldDetails, false);
        }

        /// <summary>
        /// 获取控制对象参数
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">Viz场景层</param>
        /// <param name="treeNodePath">场景数路径</param>
        /// <param name="parameter">参数</param>
        /// <returns>描述</returns>
        public string GetControlObjectParameter(ConnModel conn, VizScene scene, string treeNodePath, VizControlObjectParameters parameter)
        {
            string cmd = $"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*{parameter} GET";
            string result = conn.EndpointManager.Request(cmd);

            return result;
        }

        /// <summary>
        /// 获取控制对象返回值
        /// </summary>
        /// <remarks>
        /// 返回结果按照“:”进行分割
        /// FieldIdentifier:VizID_SetGetfunction:Type:Min:Max:MaxChar:Description:AuxField:
        /// </remarks>
        /// <param name="conn">连接</param>
        /// <param name="scene">Viz场景层</param>
        /// <param name="treeNodePath">场景树路径</param>
        /// <returns>控制对象返回值</returns>
        public string GetControlObjectResult(ConnModel conn, VizScene scene, string treeNodePath)
        {
            conn.EndpointManager.Send($"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*in SET LIST");
            string result = conn.EndpointManager.Request($"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*result GET");

            return result;
        }

        /// <summary>
        /// 获取控制对象字段值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">Viz场景层</param>
        /// <param name="treeNodePath">场景树路径</param>
        /// <param name="fieldIdentifier">字段</param>
        /// <returns>字段值</returns>
        public string GetControlFieldValue(ConnModel conn, VizScene scene, string treeNodePath, string fieldIdentifier)
        {
            conn.EndpointManager.Send($"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*in SET ON {fieldIdentifier} GET");
            string result = conn.EndpointManager.Request($"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*result GET");

            return result;
        }

        /// <summary>
        /// 设置控制对象值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">场景层</param>
        /// <param name="treeNodePath">场景节点路径</param>
        /// <param name="fieldIdentifier">字段</param>
        /// <param name="value">值</param>
        public void SetControlObjectValue(ConnModel conn, VizScene scene, string treeNodePath, string fieldIdentifier, string value)
        {
            string str = $"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*in SET ON {fieldIdentifier} SET {value}";

            conn.EndpointManager.Send(str);
        }

        /// <summary>
        /// 设置时钟的发送命令字符串
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="scene"></param>
        /// <param name="treeNodePath"></param>
        /// <param name="fieldIdentifier"></param>
        /// <param name="upValue"></param>
        /// <param name="downValue"></param>
        /// <param name="cmd"></param>
        public void SetControlObjectClockCmd(ConnModel conn, VizScene scene, string treeNodePath, string fieldIdentifier, string upValue, string downValue, string cmd)
        {
            string str = $"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*in SET ON {fieldIdentifier} SET *TIME SET {upValue},*LIMIT SET {downValue},*DIRECTION SET {cmd}";

            conn.EndpointManager.Send(str);
        }

        /// <summary>
        /// 设置控制对象值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="scene">层</param>
        public void SetControlObject(ConnModel conn, ControlObjectModel obj, VizScene scene)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append($"{scene}*TREE*{obj.TreeNodePath}*FUNCTION*ControlObject*in SET ON ");
            foreach (ControlFieldNodeModel field in obj.AllFiledNodes)
            {
                // 自定义字段不通过该方法上板
                if (field.IsCustom)
                    continue;

                sb.Append($"{field.FieldIdentifier} SET {field.Value}\\0");
            }

            conn.EndpointManager.Send(sb.ToString());
        }

        /// <summary>
        /// 设置列表控制对象的值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="scene">场景层</param>
        /// <param name="treeNodePath">场景节点路径</param>
        /// <param name="listName">列表名称</param>
        /// <param name="listLine">列表值位序</param>
        /// <param name="fieldIdentifier">字段</param>
        /// <param name="value">值</param>
        public void SetControlObjectListValue(ConnModel conn, VizScene scene, string treeNodePath, string listName, int listLine, string fieldIdentifier, string value)
        {
            conn.EndpointManager.Send($"{scene}*TREE*{treeNodePath}*FUNCTION*ControlObject*in SET WITH {listName} INDEX {listLine} ON {fieldIdentifier} SET {value}");
        }

        /// <summary>
        /// 设置控制字段聚焦
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="field">控制字段</param>
        public void ShowFocus(ConnModel conn, ControlObjectModel obj, ControlFieldNodeModel field)
        {
            if (conn == null)
                throw new ArgumentNullException(nameof(conn));

            VizConfigEntity config = ApplicationDomainEx.VizConfig;

            if (config.EngineFullType == EngineFullType.VIZ_Eng3)
            {
                conn.EndpointManager.Send($"RENDERER*TREE*{obj.TreeNodePath}*FUNCTION*ControlObject*in SET FOCUS {field.FieldIdentifier}");
            }
            else if (config.EngineFullType == EngineFullType.VIZ_Eng4)
            {
                conn.EndpointManager.Send($"{ApplicationDomainEx.VizPreviewRenderer}*TREE*{obj.TreeNodePath}*FUNCTION*ControlObject*in SET FOCUS {field.FieldIdentifier}");
            }
        }

        /// <summary>
        /// 设置控制字段聚焦
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="field">控制字段</param>
        /// <param name="listLine">行数</param>
        /// <param name="fieldIdentifier">字段名</param>
        public void ShowFocus(ConnModel conn, ControlObjectModel obj, ControlFieldNodeModel field, int listLine, string fieldIdentifier)
        {
            if (conn == null)
                throw new ArgumentNullException(nameof(conn));

            VizConfigEntity config = ApplicationDomainEx.VizConfig;

            if (config.EngineFullType == EngineFullType.VIZ_Eng3)
            {
                conn.EndpointManager.Send($"RENDERER*TREE*{obj.TreeNodePath}*FUNCTION*ControlObject*in SET WITH {field.FieldIdentifier} INDEX {listLine} FOCUS {fieldIdentifier}");
            }
            else if (config.EngineFullType == EngineFullType.VIZ_Eng4)
            {
                conn.EndpointManager.Send($"{ApplicationDomainEx.VizPreviewRenderer}*TREE*{obj.TreeNodePath}*FUNCTION*ControlObject*in SET WITH {field.FieldIdentifier} INDEX {listLine} FOCUS {fieldIdentifier}");
            }
        }

        /// <summary>
        /// 控制对象停止仓储
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="vizID">VizID</param>
        public void ControlObjectStoreStops(ConnModel conn, string vizID)
        {
            conn.EndpointManager.Send($"#{vizID}*FUNCTION*ControlObject*store_stops INVOKE");
        }

        // --------------------------------------------------------------------------------------------------
        // 切换场景

        /// <summary>
        /// 获取控制对象值字符串
        /// </summary>
        /// <param name="obj">控制对象</param>
        /// <returns>控制对象值字符串</returns>
        public string GetControlObjectStringWithTransitionLogic(ControlObjectModel obj)
        {
            if (obj == null || obj.AllFiledNodes == null || obj.AllFiledNodes.Count == 0)
                return string.Empty;

            StringBuilder sb = new StringBuilder();
            foreach (ControlFieldNodeModel field in obj.AllFiledNodes)
            {
                // 自定义字段不通过该方法上板
                if (field.IsCustom)
                    continue;

                sb.Append($"{field.FieldIdentifier} SET {field.Value}\\0");
            }

            return sb.ToString();
        }

        /// <summary>
        /// 设置切换逻辑的控制对象值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="pageBase">页</param>
        public void SetControlObjectOtherWithTransitionLogic(ConnModel conn, ControlObjectModel obj, PageModelBase pageBase)
        {
            string bgScenePath = $"{pageBase.GetSceneParent()}/{pageBase.BackgroundScene}";

            StringBuilder sb = new StringBuilder();
            string value = this.GetControlObjectStringWithTransitionLogic(obj);
            sb.Append($"SCENE*{bgScenePath}*TREE*${pageBase.LayerIdentifier}$other$object*FUNCTION*ControlObject*in SET ON {value}");

            conn.EndpointManager.Send(sb.ToString());
        }

        /// <summary>
        /// 设置切换逻辑的控制对象值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="pageBase">页</param>
        public void SetControlObjectCurrentWithTransitionLogic(ConnModel conn, ControlObjectModel obj, PageModelBase pageBase)
        {
            string bgScenePath = $"{pageBase.GetSceneParent()}/{pageBase.BackgroundScene}";

            StringBuilder sb = new StringBuilder();
            string value = this.GetControlObjectStringWithTransitionLogic(obj);
            sb.Append($"SCENE*{bgScenePath}*TREE*${pageBase.LayerIdentifier}$current$object*FUNCTION*ControlObject*in SET ON {value}");

            conn.EndpointManager.Send(sb.ToString());
        }

        /// <summary>
        /// 设置切换逻辑的控制对象值
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="obj">控制对象</param>
        /// <param name="pageBase">页</param>
        public void SetCustomControlObjectWithTransitionLogic(ConnModel conn, ControlObjectModel obj, PageModelBase pageBase)
        {
            if (obj.AllFiledNodes == null || obj.AllFiledNodes.Count == 0)
                return;

            List<ControlFieldNodeModel> list = obj.AllFiledNodes.Where(p => p.IsCustom).ToList();

            if (list.Count == 0)
                return;

            // FieldIdentifier|Value*FieldIdentifier|Value
            List<string> field_infos = list.Select(p => string.Format("{0}|{1}", p.FieldIdentifier, p.Value)).ToList();
            string command = string.Join("*", field_infos);

            conn.EndpointManager.Send(string.Format(VizEngineCommands.SCRIPT_INVOKE, ApplicationConstants.VIZ_COMMAND_CUSTOM_CONTROL_FIELD_SET, command));
        }

        /// <summary>
        /// 根据控制字段实体创建控制对象字段模型
        /// </summary>
        /// <param name="entity">控制字段实体</param>
        /// <returns>控制对象字段模型</returns>
        public ControlFieldNodeModel CreateControlFieldNodeModeFromEntity(ControlFieldEntity entity)
        {
            if (string.IsNullOrWhiteSpace(entity.FieldDetail))
                return null;

            string[] pars = entity.FieldDetail.Split(':');
            string num = pars[1].Split('*').FirstOrDefault();

            ControlFieldNodeModel node = new ControlFieldNodeModel();

            node.FieldDetail = entity.FieldDetail;
            node.FieldIdentifier = pars[0];
            node.Num = num;
            node.TypeSchema = pars[2];
            node.Type = this.GetControlFieldType(node.TypeSchema);
            node.Value = entity.Value;

            if (pars.Length >= 7)
            {
                node.Description = pars[6];
            }

            return node;
        }

        /// <summary>
        /// 获取控制字段类型
        /// </summary>
        /// <param name="type">字段类型</param>
        /// <returns>控制对象字段类型</returns>
        public VizControlFieldType GetControlFieldType(string type)
        {
            if (type == "text")
                return VizControlFieldType.text;

            if (type == "bool")
                return VizControlFieldType.boolean;

            if (type == "image")
                return VizControlFieldType.image;

            if (type == "richtext")
                return VizControlFieldType.richtext;

            if (type == "integer")
                return VizControlFieldType.integer;

            if (type == "float")
                return VizControlFieldType.@float;

            if (type == "duplet")
                return VizControlFieldType.duplet;

            if (type == "triplet")
                return VizControlFieldType.triplet;

            if (type == "font")
                return VizControlFieldType.font;

            if (type == "radio")
                return VizControlFieldType.radio;

            if (type == "scroll_elements")
                return VizControlFieldType.scroll_elements;

            if (type.StartsWith("<?xml"))
                return VizControlFieldType.list;

            if (type == "custom_video")
                return VizControlFieldType.custom_video;

            if (type == "clock")
                return VizControlFieldType.clock;

            if (type == "color")
                return VizControlFieldType.color;

            return VizControlFieldType.none;
        }

        // =======================================================================
        // Private Function
        // =======================================================================

        /// <summary>
        /// 更新控制对象字段
        /// </summary>
        /// <param name="conn">连接</param>
        /// <param name="model">控制字段模型</param>
        /// <param name="fieldDetails">字段描述</param>
        /// <param name="isGetValueFromViz">是否从Viz获取字段值</param>
        private void UpdateControlObjectField(ConnModel conn, ControlObjectModel model, string fieldDetails, bool isGetValueFromViz)
        {
            foreach (string fieldDetail in fieldDetails.Split('\n'))
            {
                // 返回示例： BTNAME:#10245*GEOM*TEXT:text:::-1:BTNAME:single_line, location_id=#10245, location=2/3/5

                if (string.IsNullOrWhiteSpace(fieldDetail))
                    continue;

                string[] pars = fieldDetail.Split(':');
                string num = pars[1].Split('*').FirstOrDefault();

                ControlFieldNodeModel node = new ControlFieldNodeModel();

                node.FieldDetail = fieldDetail;
                node.FieldIdentifier = pars[0];
                node.Num = num;
                node.TypeSchema = pars[2];
                node.Type = this.GetControlFieldType(node.TypeSchema);
                if (isGetValueFromViz)
                {
                    node.Value = this.GetControlFieldValue(conn, VizScene.MAIN_SCENE, model.TreeNodePath, node.FieldIdentifier);
                }

                if (pars.Length >= 7)
                {
                    node.Description = pars[6];
                }

                model.AllFiledNodes.Add(node);
            }

            // Step 6. 根据字段FieldIdentifier构建树形结构
            List<ControlFieldNodeModel> fieldNodes = new List<ControlFieldNodeModel>();
            List<ControlFieldNodeModel> allNodes = model.AllFiledNodes.ToList();

            foreach (ControlFieldNodeModel node in model.AllFiledNodes)
            {
                if (!node.FieldIdentifier.Contains("."))
                {
                    // 顶级节点
                    fieldNodes.Add(node);
                    continue;
                }

                // 更新控制字段父级节点
                this.UpdateControlObjectFieldParent(allNodes, fieldNodes, node);
            }

            model.FieldNodes = fieldNodes;

            // Step 7. 更新自定义字段
            this.UpdateCustomControlOjbectField(conn, model, model.CustomFieldDetails, isGetValueFromViz);
        }

        /// <summary>
        /// 更新控制字段父级对象
        /// </summary>
        /// <param name="allNodes">所有节点</param>
        /// <param name="fieldNodes">顶级节点集合</param>
        /// <param name="node">当前节点</param>
        private void UpdateControlObjectFieldParent(List<ControlFieldNodeModel> allNodes, List<ControlFieldNodeModel> fieldNodes, ControlFieldNodeModel node)
        {
            int lastIndex = node.FieldIdentifier.LastIndexOf('.');
            if (lastIndex <= 0)
                return;

            string parentRoute = node.FieldIdentifier.Substring(0, lastIndex);
            ControlFieldNodeModel parent = allNodes.FirstOrDefault(p => p.FieldIdentifier == parentRoute);

            if (parent != null)
            {
                parent.Items.Add(node);
                return;
            }

            // 补节点
            parent = new ControlFieldNodeModel();
            parent.FieldIdentifier = parentRoute;
            parent.Items.Add(node);
            allNodes.Add(parent);

            // 顶级节点
            if (!parent.FieldIdentifier.Contains('.'))
            {
                fieldNodes.Add(parent);
                return;
            }

            this.UpdateControlObjectFieldParent(allNodes, fieldNodes, parent);
        }
    }
}
