Imports System.Drawing
Imports System.Text
Imports System.Xml
Imports UTS_Core.UTSModule.Production
Imports UTS_Core.UTSModule.Test.Command

Namespace UTSModule.Station
    Public NotInheritable Class RowNode

#Region "初始化"
        Sub New()
            RowType = RowTypeEnum.Flow
            AuthByType(RowType)

            Pause = False
            Action = True
            RecordName = String.Empty

            Retry = 0
            RetryInterval = 100

            [Label] = String.Empty
            Description = String.Empty

            ErrorCode = String.Empty
            ErrorMessage = String.Empty

            CommandType = String.Empty
            Command = String.Empty
            Parameters = New List(Of TestCmdParam)

            SaveToDb = False
            ControlType = String.Empty

            Children = New List(Of RowNode)()

            Expanded = True
            AllChildCount = 0
            RowNodes = New RowNodeCollection(Me)

            RowListIndex = 0
            RowList = New List(Of RowNode)()
            RowList.Add(Me)
        End Sub

        ''' <summary>
        ''' 模块名称
        ''' </summary>
        ''' <returns></returns>
        Public Property [Label] As String

        ''' <summary>
        ''' 控制命令类型
        ''' </summary>
        ''' <returns></returns>
        Public Property ControlType As String

        ''' <summary>
        ''' 当前流程步骤的解释
        ''' </summary>
        ''' <returns></returns>
        Public Property Description As String

        ''' <summary>
        ''' 调试模式下运行到当前节点后,暂停运行
        ''' </summary>
        ''' <returns></returns>
        Public Property Pause() As Boolean

        ''' <summary>
        ''' 当前流程步骤是否允许执行
        ''' </summary>
        ''' <returns></returns>
        Public Property Action As Boolean

        ''' <summary>
        ''' 当前流程步骤是否会被执行
        ''' </summary>
        ''' <returns></returns>
        Public Property IsRunning As Boolean

        ''' <summary>
        '''  当前流程步骤执行结果是否保存至数据库,FALSE则为临时变量
        ''' </summary>
        ''' <returns></returns>
        Public Property SaveToDb() As Boolean

        Public Property RecordName As String


        Public Property Retry As Integer
        Public Property RetryInterval As Integer


        Public Property ErrorCode As String
        Public Property ErrorMessage As String

        Public Property CommandType As String
        Public Property Command As String

        Public Property Parameters() As List(Of TestCmdParam)

        Private _rowType As RowTypeEnum
        ''' <summary>
        ''' 行的类型
        ''' </summary>
        ''' <returns></returns>
        Public Property RowType As RowTypeEnum
            Get
                Return _rowType
            End Get
            Set
                _rowType = Value
                AuthByType(Value)
            End Set
        End Property

        ''' <summary>
        ''' 行节点关联的站流程
        ''' </summary>
        ''' <returns></returns>
        Public Property StationPlan() As StationTestPlan

        ''' <summary>
        ''' 行节点执行结果信息
        ''' </summary>
        ''' <returns></returns>
        Public Property TestReturn As TestCommandReturn


        ''' <summary>
        ''' 节点树的所有节点集合
        ''' </summary>
        ''' <returns></returns>
        Public Property RowList As List(Of RowNode)


        ''' <summary>
        ''' 节点所属节点数组的位置,从0开始，即头结点的的索引
        ''' </summary>
        ''' <returns></returns>
        Public Property RowListIndex() As Integer

        ''' <summary>
        ''' 节点的级别,可见节点级别从0开始
        ''' </summary>
        ''' <returns></returns>
        Public Property RowLever As Integer

        ''' <summary>
        ''' 节点在父节点中的索引,可见节点级别从0开始
        ''' </summary>
        ''' <returns></returns>
        Public Property RowIndex As Integer

        ''' <summary>
        ''' 记录总使用的说明内容
        ''' </summary>
        ''' <returns></returns>
        Public Property Desc4Record As String


        ''' <summary>
        ''' 子节点总数
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property Count() As Integer
            Get
                Return Children.Count
            End Get
        End Property

        ''' <summary>
        ''' 所有子节点总数
        ''' </summary>
        ''' <returns></returns>
        Public Property AllChildCount() As Integer


        ''' <summary>
        ''' 行下包含的子行集合
        ''' </summary>
        ''' <returns></returns>
        Public Property RowNodes() As RowNodeCollection

        ''' <summary>
        ''' 当前节点的同级上一节点，若当前节点为首节点则返回nothing
        ''' </summary>
        ''' <returns></returns>
        Public Property PrevNode() As RowNode

        ''' <summary>
        ''' 当前节点的同级下一节点，若当前节点为尾节点则返回nothing
        ''' </summary>
        ''' <returns></returns>
        Public Property NextNode() As RowNode


        ''' <summary>
        ''' 当前节点的父节点
        ''' </summary>
        ''' <returns></returns>
        Public Property ParentNode() As RowNode

        ''' <summary>
        ''' 当前节点树的起始节点
        ''' </summary>
        ''' <returns></returns>
        Public Property HeadNode() As RowNode

        ''' <summary>
        ''' 内部缓存子节点
        ''' </summary>
        Friend Children As List(Of RowNode)

        ''' <summary>
        ''' 处于展开状态
        ''' </summary>
        ''' <returns></returns>
        Public Property Expanded() As Boolean

        ''' <summary>
        ''' 是否允许删除当前节点
        ''' </summary>
        ''' <returns></returns>
        Public Property CanDelete() As Boolean

        ''' <summary>
        ''' 是否允许添加子节点
        ''' </summary>
        ''' <returns></returns>
        Public Property CanAddChildNode() As Boolean


        ''' <summary>
        ''' 允许操作当前节点内容
        ''' </summary>
        ''' <returns></returns>
        Public Property CanChangeContent() As Boolean

        ''' <summary>
        ''' 允许移动节点改变节点的级别
        ''' </summary>
        ''' <returns></returns>
        Public Property CanChangeLever() As Boolean

        ''' <summary>
        ''' 允许移动节点移动
        ''' </summary>
        ''' <returns></returns>
        Public Property CanMove() As Boolean

        ''' <summary>
        ''' 当前节点是否处于重试状态
        ''' </summary>
        ''' <returns></returns>
        Public Property IsRetry As Boolean

        Private Sub AuthByType(type As RowTypeEnum)
            Select Case type
                Case RowTypeEnum.FixedModule
                    CanAddChildNode = True
                    CanChangeContent = False
                    CanDelete = False
                    CanChangeLever = False
                    CanMove = False
                Case RowTypeEnum.Module
                    CanAddChildNode = True
                    CanChangeContent = True
                    CanDelete = True
                    CanChangeLever = True
                    CanMove = True
                Case RowTypeEnum.Control
                    CanAddChildNode = True
                    CanChangeContent = True
                    CanDelete = True
                    CanChangeLever = True
                    CanMove = True

                Case RowTypeEnum.Flow
                    CanAddChildNode = True
                    CanChangeContent = True
                    CanDelete = True
                    CanChangeLever = True
                    CanMove = True

            End Select
        End Sub
#End Region

#Region "节点操作"
        ''' <summary>
        ''' 展开节点
        ''' </summary>
        Public Sub Expand()
            If Expanded Then Return
            Expanded = True
        End Sub

        ''' <summary>
        ''' 折叠节点
        ''' </summary>
        Public Sub Collapse()
            If Expanded = False Then Return
            Expanded = False
        End Sub

        ''' <summary>
        ''' 展开或折叠节点
        ''' </summary>
        Public Sub Toggle()
            Expanded = Not Expanded
        End Sub

        ''' <summary>
        ''' 增加子节点
        ''' </summary>
        Public Sub AddNode(node As RowNode)
            If CanAddChildNode Then
                RowNodes.Add(node)
            Else
                ParentNode.InsertNode(RowIndex + 1, node)
            End If
        End Sub


        ''' <summary>
        ''' 插入子节点
        ''' </summary>
        Public Sub InsertNode(index As Integer, childNode As RowNode)
            If CanAddChildNode Then
                RowNodes.Insert(index, childNode)
            Else
                ParentNode.InsertNode(index, childNode)
            End If
            ' ParentNode.InsertNode(index, childNode)
        End Sub


        Public Sub RemoveChildNode(childNode As RowNode)
            If childNode.CanDelete = False Then Return
            RowNodes.Remove(childNode)
        End Sub

        Public Sub RemoveChildAt(index As Integer)
            If index >= RowNodes.Count Then Return
            Dim child As RowNode = CType(RowNodes.Item(index), RowNode)
            If child.CanDelete = False Then Return
            RowNodes.RemoveAt(index)
        End Sub

        ''' <summary>
        ''' 移除本身节点
        ''' </summary>
        Public Function Remove() As Boolean
            ' If CanDelete = False Then Return False
            ParentNode.RowNodes.Remove(Me)
            Return True
        End Function

        ''' <summary>
        ''' 清空节点所有子节点
        ''' </summary>
        Public Sub Clear()
            RowNodes.Clear()
        End Sub



        ''' <summary>
        ''' 节点上移
        ''' </summary>
        Public Sub MoveUp()
            If RowIndex = 0 Then Return

            If Remove() = False Then Return
            ParentNode.RowNodes.Insert(RowIndex - 1, Me)
        End Sub

        ''' <summary>
        ''' 节点下移
        ''' </summary>
        Public Sub MoveDown()
            If RowIndex = ParentNode.RowNodes.Count - 1 Then Return

            If Remove() = False Then Return
            ParentNode.RowNodes.Insert(RowIndex + 1, Me)
        End Sub

        ''' <summary>
        ''' 节点左移
        ''' </summary>
        Public Sub MoveLeft()
            If RowLever = 0 Then Return
            If Remove() = False Then Return
            ParentNode.ParentNode.RowNodes.Insert(ParentNode.RowIndex + 1, Me)
        End Sub

        ''' <summary>
        ''' 节点右移
        ''' </summary>
        Public Sub MoveRight()
            If RowIndex = 0 Then Return
            ' If CanChangeLever = False Then Return

            If Remove() = False Then Return
            Dim rNode As RowNode = CType(ParentNode.RowNodes(RowIndex - 1), RowNode)
            rNode.RowNodes.Add(Me)

        End Sub


        ''' <summary>
        ''' 节点深复制,创建一个完全相同信息的节点
        ''' </summary>
        ''' <returns></returns>
        Public Function Clone() As RowNode
            Dim cpNode As New RowNode

            With cpNode
                .RowListIndex = RowListIndex

                .Pause = Pause
                .ControlType = ControlType
                .SaveToDb = SaveToDb

                .RowType = RowType

                .Action = Action
                .RecordName = RecordName

                .Retry = Retry
                .RetryInterval = RetryInterval

                .[Label] = String.Copy(Label)
                .Description = String.Copy(Description)

                .ErrorCode = String.Copy(ErrorCode)
                .ErrorMessage = String.Copy(ErrorMessage)

                .CommandType = String.Copy(CommandType)
                .Command = String.Copy(Command)

                .Parameters = New List(Of TestCmdParam)
                For Each param As TestCmdParam In Parameters
                    .Parameters.Add(param.Clone())
                Next

                '.RowNodes = New RowNodeCollection(cpNode)
                '.Children = New List(Of RowNode)()

                ''todo:克隆功能待重写

                'For Each child As RowNode In Children
                '    .RowNodes.Add(child.Clone())
                'Next
            End With

            Return cpNode
        End Function

        Public Sub CopyFrom(node As RowNode)
            With node
                .RowListIndex = RowListIndex

                Pause = .Pause
                ControlType = .ControlType
                SaveToDb = .SaveToDb

                RowType = .RowType
                Action = .Action
                RecordName = .RecordName
                Retry = .Retry
                RetryInterval = .RetryInterval
                [Label] = String.Copy(.Label)
                Description = String.Copy(.Description)
                ErrorCode = String.Copy(.ErrorCode)
                ErrorMessage = String.Copy(.ErrorMessage)
                CommandType = String.Copy(.CommandType)
                Command = String.Copy(.Command)
                Parameters.Clear()
                For Each param As TestCmdParam In .Parameters
                    Parameters.Add(param.Clone())
                Next
            End With
        End Sub
#End Region

#Region "节点样式"
        Public Enum RowTypeEnum
            ''' <summary>
            ''' 固定模块
            ''' </summary>
            FixedModule
            ''' <summary>
            ''' 模块,可以当作跳转入口
            ''' </summary>
            [Module]
            ''' <summary>
            ''' 控制
            ''' </summary>
            Control
            ''' <summary>
            ''' 流程
            ''' </summary>
            Flow
        End Enum

#End Region

#Region "节点风格"
        Public Shared Property NodeStyles() As Dictionary(Of RowTypeEnum, RowNodeStyle)


        ''' <summary>
        ''' 默认的初始化节点风格
        ''' </summary>
        Public Shared Sub InitNodeStyles()
            NodeStyles = New Dictionary(Of RowTypeEnum, RowNodeStyle) From {
                {RowTypeEnum.FixedModule, New RowNodeStyle(RowTypeEnum.FixedModule)},
                {RowTypeEnum.Module, New RowNodeStyle(RowTypeEnum.Module)},
                {RowTypeEnum.Control, New RowNodeStyle(RowTypeEnum.Control)},
                {RowTypeEnum.Flow, New RowNodeStyle(RowTypeEnum.Flow)}
                }

        End Sub


        Private Shared Function LoadNodeStyle(nodeList As XmlNodeList) As RowNodeStyle
            Dim nodeStyle As New RowNodeStyle

            Dim xe As XmlElement
            For Each node As XmlNode In nodeList
                xe = CType(node, XmlElement)
                Select Case xe.LocalName
                    Case "Font"
                        Dim fStyle As FontStyle = CType([Enum].Parse(GetType(FontStyle), xe.GetAttribute("FontStyle")), FontStyle)
                        Dim fSize As Single = CSng(xe.GetAttribute("FontSize"))

                        nodeStyle.NodeFont = New Font(xe.InnerText, fSize, fStyle)
                    Case "ForeColor"
                        nodeStyle.NodeForeColor = Color.FromArgb(CInt(xe.InnerText))
                    Case "BackColor"
                        nodeStyle.NodeBackColor = Color.FromArgb(CInt(xe.InnerText))

                    Case "ImageKey"
                        nodeStyle.NodeImageKey = xe.InnerText

                    Case "ShowRecord"
                        nodeStyle.ShowRecord = CType(xe.InnerText, Boolean)
                    Case "ShowLabel"
                        nodeStyle.ShowLabel = CType(xe.InnerText, Boolean)
                    Case "ShowDescription"
                        nodeStyle.ShowDescription = CType(xe.InnerText, Boolean)

                    Case "ShowAction"
                        nodeStyle.ShowAction = CType(xe.InnerText, Boolean)
                    Case "ShowRecord"
                        nodeStyle.ShowRecord = CType(xe.InnerText, Boolean)

                    Case "ShowRetry"
                        nodeStyle.ShowRetry = CType(xe.InnerText, Boolean)
                    Case "ShowRetryInterval"
                        nodeStyle.ShowRetryInterval = CType(xe.InnerText, Boolean)

                    Case "ShowErrorCode"
                        nodeStyle.ShowErrorCode = CType(xe.InnerText, Boolean)
                    Case "ShowErrorMessage"
                        nodeStyle.ShowErrorMessage = CType(xe.InnerText, Boolean)

                    Case "ShowCommand"
                        nodeStyle.ShowCommand = CType(xe.InnerText, Boolean)
                    Case "ShowParameter"
                        nodeStyle.ShowParameter = CType(xe.InnerText, Boolean)
                    Case Else
                        Throw New Exception($"LoadRowNodes Unknown LocalName:{xe.LocalName}")
                End Select
            Next

            Return nodeStyle
        End Function

        ''' <summary>
        ''' 从本地文件中初始化节点风格
        ''' </summary>
        ''' <param name="path"></param>
        Public Shared Sub LoadNodeStyles(path As String)
            NodeStyles = New Dictionary(Of RowTypeEnum, RowNodeStyle)()

            Dim xd As New XmlDocument()
            xd.Load(path)

            Dim xe As XmlElement
            Dim nodeList As XmlNodeList = xd.SelectSingleNode($"NodeStyles").ChildNodes
            For Each node As XmlNode In nodeList
                xe = CType(node, XmlElement)
                Select Case xe.LocalName
                    Case "NodeStyle"
                        Dim type As RowTypeEnum = CType([Enum].Parse(GetType(RowTypeEnum), xe.GetAttribute("Type")), RowTypeEnum)

                        NodeStyles.Add(type, LoadNodeStyle(xe.ChildNodes))
                    Case Else
                        Throw New Exception($"LoadNodeStyles Unknown LocalName:{xe.LocalName}")
                End Select
            Next

        End Sub

        Public Shared Sub SaveNodeStyles(path As String)
            Dim xws As New XmlWriterSettings
            With xws
                .Indent = True
                .NewLineOnAttributes = False
                .Encoding = New UTF8Encoding(False)
            End With

            Using xw As XmlWriter = XmlWriter.Create(path, xws)
                xw.WriteStartDocument()
                xw.WriteStartElement($"NodeStyles") '创建跟节点


                For Each nodeStyle As KeyValuePair(Of RowTypeEnum, RowNodeStyle) In NodeStyles
                    xw.WriteStartElement($"NodeStyle") '创建表属性节点
                    xw.WriteAttributeString("Type", nodeStyle.Key.ToString())


                    xw.WriteStartElement($"Font") '创建表属性节点
                    xw.WriteAttributeString("FontSize", nodeStyle.Value.NodeFont.Size.ToString())
                    xw.WriteAttributeString("FontStyle", nodeStyle.Value.NodeFont.Style.ToString())
                    xw.WriteString(nodeStyle.Value.NodeFont.Name.ToString())
                    xw.WriteEndElement()


                    xw.WriteElementString("ForeColor", nodeStyle.Value.NodeForeColor.ToArgb().ToString())
                    xw.WriteElementString("BackColor", nodeStyle.Value.NodeBackColor.ToArgb().ToString())

                    xw.WriteElementString("ImageKey", nodeStyle.Value.NodeImageKey)


                    If nodeStyle.Value.ShowRowType Then xw.WriteElementString("ShowRecord", nodeStyle.Value.ShowRowType.ToString())
                    If nodeStyle.Value.ShowLabel Then xw.WriteElementString("ShowLabel", nodeStyle.Value.ShowLabel.ToString())
                    If nodeStyle.Value.ShowDescription Then xw.WriteElementString("ShowDescription", nodeStyle.Value.ShowDescription.ToString())

                    If nodeStyle.Value.ShowAction Then xw.WriteElementString("ShowAction", nodeStyle.Value.ShowAction.ToString())
                    If nodeStyle.Value.ShowRecord Then xw.WriteElementString("ShowRecord", nodeStyle.Value.ShowRecord.ToString())

                    If nodeStyle.Value.ShowRetry Then xw.WriteElementString("ShowRetry", nodeStyle.Value.ShowRetry.ToString())
                    If nodeStyle.Value.ShowRetryInterval Then xw.WriteElementString("ShowRetryInterval", nodeStyle.Value.ShowRetryInterval.ToString())

                    If nodeStyle.Value.ShowErrorCode Then xw.WriteElementString("ShowErrorCode", nodeStyle.Value.ShowErrorCode.ToString())
                    If nodeStyle.Value.ShowErrorMessage Then xw.WriteElementString("ShowErrorMessage", nodeStyle.Value.ShowErrorMessage.ToString())

                    If nodeStyle.Value.ShowCommand Then xw.WriteElementString("ShowCommand", nodeStyle.Value.ShowCommand.ToString())
                    If nodeStyle.Value.ShowParameter Then xw.WriteElementString("ShowParameter", nodeStyle.Value.ShowParameter.ToString())

                    xw.WriteEndElement()
                Next


                xw.WriteEndElement()
                xw.WriteEndDocument()
            End Using


        End Sub
#End Region

#Region "节点保存与加载"
        Public Sub SaveRowNode(xw As XmlWriter)
            xw.WriteStartElement($"RowNode") '创建单元格节点

            xw.WriteElementString("RowType", RowType.ToString())

            If String.IsNullOrEmpty(Label) = False Then xw.WriteElementString("Label", Label)
            xw.WriteElementString("Action", Action.ToString())

            If String.IsNullOrEmpty(ControlType) = False Then xw.WriteElementString("ControlType", ControlType)

            If String.IsNullOrEmpty(CommandType) = False Then xw.WriteElementString("CommandType", CommandType)
            If String.IsNullOrEmpty(Command) = False Then xw.WriteElementString("Command", Command)
            If String.IsNullOrEmpty(Description) = False Then xw.WriteElementString("Description", Description)

            xw.WriteElementString("Retry", Retry.ToString())
            xw.WriteElementString("RetryInterval", RetryInterval.ToString())

            xw.WriteElementString("SaveToDb", SaveToDb.ToString())
            If String.IsNullOrEmpty(RecordName) = False Then xw.WriteElementString("RecordName", RecordName)


            If String.IsNullOrEmpty(ErrorCode) = False Then xw.WriteElementString("ErrorCode", ErrorCode)
            If String.IsNullOrEmpty(ErrorMessage) = False Then xw.WriteElementString("ErrorMessage", ErrorMessage)

            For Each parameter As TestCmdParam In Parameters
                xw.WriteStartElement($"Parameter") '创建跟节点

                xw.WriteAttributeString("Type", parameter.Type)
                xw.WriteAttributeString("Desc", parameter.Desc)
                xw.WriteAttributeString("LowerLimit", parameter.LowerLimit)
                xw.WriteAttributeString("UpperLimit", parameter.UpperLimit)
                xw.WriteString(parameter.Value)

                xw.WriteEndElement()
            Next

            If RowNodes.Count > 0 Then
                SaveRowNodes(xw, RowNodes)
            End If

            xw.WriteEndElement()
        End Sub


        Public Shared Sub SaveRowNodes(xw As XmlWriter, nodes As RowNodeCollection)
            xw.WriteStartElement($"RowNodes") '创建单元格节点

            For Each node As RowNode In nodes
                node.SaveRowNode(xw)
            Next

            xw.WriteEndElement()
        End Sub

        ''' <summary>
        ''' 导出为XML文件
        ''' </summary>
        ''' <param name="path">文件路径</param>
        Public Sub ExportToXml(path As String)
            Dim xws As New XmlWriterSettings
            With xws
                .Indent = True
                .NewLineOnAttributes = False
                .Encoding = New UTF8Encoding(False)
            End With

            Using xw As XmlWriter = XmlWriter.Create(path, xws)
                xw.WriteStartDocument()

                SaveRowNode(xw)

                xw.WriteEndDocument()
            End Using
        End Sub

        ''' <summary>
        ''' 加载行节点
        ''' </summary>
        ''' <param name="nodeList"></param>
        ''' <param name="rowCollection"></param>
        Public Shared Sub LoadRowNodes(nodeList As XmlNodeList, rowCollection As RowNodeCollection)
            Dim xe As XmlElement
            For Each node As XmlNode In nodeList
                xe = CType(node, XmlElement)
                Select Case xe.LocalName
                    Case "RowNode"
                        Dim row As New RowNode
                        rowCollection.Add(row)
                        row.LoadFormXmlNodeList(xe.ChildNodes)
                    Case Else
                        Throw New Exception($"LoadRowNodes Unknown LocalName:{xe.LocalName}")
                End Select
            Next
        End Sub


        Public Sub LoadFormXmlNodeList(nodeList As XmlNodeList)
            Dim xe As XmlElement
            For Each node As XmlNode In nodeList
                xe = CType(node, XmlElement)
                Select Case xe.LocalName
                    Case "RowType"
                        RowType = CType([Enum].Parse(GetType(RowTypeEnum), xe.InnerText), RowTypeEnum)

                    Case "Description"
                        Description = xe.InnerText

                    Case "Label"
                        Label = xe.InnerText

                    Case "ControlType"
                        ControlType = xe.InnerText

                    Case "Action"
                        Action = CBool(xe.InnerText)

                    Case "SaveToDb"
                        SaveToDb = CBool(xe.InnerText)
                    Case "RecordName"
                        RecordName = xe.InnerText

                    Case "Retry"
                        Retry = CInt(xe.InnerText)
                    Case "RetryInterval"
                        RetryInterval = CInt(xe.InnerText)

                    Case "ErrorCode"
                        ErrorCode = xe.InnerText
                    Case "ErrorMessage"
                        ErrorMessage = xe.InnerText

                    Case "CommandType"
                        CommandType = xe.InnerText
                    Case "Command"
                        Command = xe.InnerText

                    Case "Parameter"
                        Dim param As New TestCmdParam With {
                            .Type = xe.GetAttribute("Type"),
                            .Desc = xe.GetAttribute("Desc"),
                            .LowerLimit = xe.GetAttribute("LowerLimit"),
                            .UpperLimit = xe.GetAttribute("UpperLimit"),
                            .Value = xe.InnerText
                        }

                        Parameters.Add(param)
                    Case "RowNodes"
                        RowNodes.Clear()
                        LoadRowNodes(xe.ChildNodes, RowNodes)
                    Case Else
                        Throw New Exception($"LoadRowNode Unknown LocalName:{xe.LocalName}")
                End Select
            Next

        End Sub

        Public Sub LoadFormXml(path As String)
            Dim xd As New XmlDocument()
            xd.Load(path)

            Dim nodeList As XmlNodeList = xd.SelectSingleNode($"RowNode").ChildNodes

            LoadFormXmlNodeList(nodeList)

        End Sub
#End Region


    End Class

End Namespace