Imports System.Drawing
Imports System.Text
Imports FlexCell
Imports UTS_Core.UTSModule.Station
Imports UTS_Core.UTSModule.Station.StationTestPlan
Imports UTS_Core.UTSModule.Test.Command

Namespace UTSModule.Test
    Public Class TestRecordGrid
        '表格各列名称对应下表
        Enum ColNames
            No
            Description
            Record
            Elapsed
            Lower
            Upper
            Result
            Max
        End Enum

        'Private ReadOnly _colWidth() As Short = {30,
        '                                            140,
        '                                            70,
        '                                            50,
        '                                            60,
        '                                            60,
        '                                            60,
        '                                            60
        '                                            }

        'Momo2023-11-10 调整宽度，适应pad竖屏
        Private ReadOnly _colWidth() As Short = {30,
                                                    120,
                                                    70,
                                                    50,
                                                    50,
                                                    50,
                                                    50,
                                                    50
                                                    }

        Private ReadOnly _colType() As CellTypeEnum = {CellTypeEnum.DefaultType,
                                                  CellTypeEnum.DefaultType,
                                                  CellTypeEnum.DefaultType,
                                                  CellTypeEnum.TextBox,
                                                  CellTypeEnum.TextBox,
                                                  CellTypeEnum.TextBox,
                                                  CellTypeEnum.TextBox,
                                                  CellTypeEnum.TextBox}

        Private _grd As Grid

        Private _plan As StationTestPlan

        ''' <summary>内置模块入口集合</summary>
        Private ReadOnly _testModules As New Dictionary(Of String, RowNode)

        ''' <summary>自定义模块下函数入口集合</summary>
        Private ReadOnly _customModules As New Dictionary(Of String, RowNode)

        Private ReadOnly _rowList As Dictionary(Of Integer, RowNode)
        Private ReadOnly _nodeList As Dictionary(Of RowNode, Integer)

        Private _callNodeList As New Dictionary(Of RowNode, List(Of Integer))
        Private _callNodeUpdateCount As New Dictionary(Of RowNode, Integer)

        Private ReadOnly _recodeRow As List(Of Integer)

        Sub New()
            _rowList = New Dictionary(Of Integer, RowNode)()
            _nodeList = New Dictionary(Of RowNode, Integer)()
            _recodeRow = New List(Of Integer)()
        End Sub

        ''' <summary>
        ''' 测试记录所关联的控件
        ''' </summary>
        ''' <returns></returns>
        Public Property Grid As Grid
            Get
                Return _grd
            End Get

            Set(value As FlexCell.Grid)
                _grd = value
                UpdateStepTestRecord()

                RemoveHandler _grd.SelChange, AddressOf Grid_SelChange

                AddHandler _grd.SelChange, AddressOf Grid_SelChange

                '点击返回选中节点
            End Set
        End Property

        ''' <summary>
        ''' 测试记录所关联的测试流程
        ''' </summary>
        ''' <returns></returns>
        Public Property StationPlan() As StationTestPlan
            Get
                Return _plan
            End Get
            Set(value As StationTestPlan)
                _plan = value
                If _grd IsNot Nothing Then
                    UpdateStepTestRecord(_plan)
                    ShowRecordRows() ' Momo 2023-11-14 默认只显示记录行
                End If
            End Set
        End Property

        Public Property ActiveNode() As RowNode


        Private Sub Grid_SelChange(sender As Object, e As Grid.SelChangeEventArgs)
            If _grd.ActiveCell Is Nothing Then Return
            If _grd.ActiveCell.Row <= 0 Then Return
            If _grd.ActiveCell.Row >= _grd.Rows Then Return
            ActiveNode = _rowList(_grd.ActiveCell.Row)

        End Sub


        ''' <summary>
        ''' 获取指定变量名的变量值
        ''' </summary>
        ''' <param name="varName">变量名</param>
        ''' <param name="localVariable">调用模块时传入的局部变量</param>
        ''' <returns></returns>
        Private Function ReplaceVar(varName As String, Optional localVariable As Dictionary(Of String, String) = Nothing) As String
            '替换变量的逻辑顺序
            '优先替换局部变量，也就是传进模块的变量
            '其次使用用户变量，也就是记录入库的变量
            '最后匹配系统变量，也就是预设带有特殊意义的字符串
            If localVariable IsNot Nothing AndAlso localVariable.ContainsKey(varName) Then
                Return localVariable(varName)
            Else
                Return varName
            End If
        End Function

        ''' <summary>
        ''' 替换字符串中使用的变量，返回替换后的字符串
        ''' </summary>
        ''' <param name="sourceString">原字符串</param>
        ''' <param name="localVariable">调用模块时传入的局部变量</param>
        ''' <returns>替换后的字符串</returns>
        Private Function ReplaceString(sourceString As String, Optional localVariable As Dictionary(Of String, String) = Nothing) As String
            Dim strBuilder As New StringBuilder
            Dim varName As New StringBuilder
            Dim findVar As Boolean

            For Each c As Char In sourceString
                If c = "{"c Then
                    If findVar Then
                        findVar = False
                        strBuilder.Append("{")
                    Else
                        findVar = True
                    End If
                ElseIf c = "}"c Then
                    If findVar Then
                        strBuilder.Append(ReplaceVar(varName.ToString()， localVariable))
                        varName.Clear()
                        findVar = False
                    Else
                        strBuilder.Append("}")
                    End If
                Else
                    If findVar Then
                        varName.Append(c)
                    Else
                        strBuilder.Append(c)
                    End If
                End If
            Next

            Return strBuilder.ToString
        End Function


        Private Sub SearchRecordName(nodes As RowNodeCollection, Optional isCallNode As Boolean = False, Optional localVariable As Dictionary(Of String, String) = Nothing)
            For Each node As RowNode In nodes
                If node.Action = False Then Continue For

                _grd.AddItem("")

                Dim row As Integer = _grd.Rows - 1
                _grd.Cell(row, ColNames.Record).Text = ReplaceString(node.RecordName, localVariable) '替换记录名称中变量
                _grd.Cell(row, ColNames.Description).Text = ReplaceString(node.Description, localVariable)

                If isCallNode Then
                    If _callNodeList.ContainsKey(node) Then
                        _callNodeList(node).Add(row)
                    Else
                        _callNodeList.Add(node, New List(Of Integer) From {row})
                    End If
                Else
                    _nodeList.Add(node, row)
                End If
                _rowList.Add(row, node)

                If node.SaveToDb Then
                    _recodeRow.Add(row)

                    _grd.Range(row, 1, _grd.Rows - 1, _grd.Cols - 1).ForeColor = Color.Black
                Else
                    _grd.Range(row, 1, _grd.Rows - 1, _grd.Cols - 1).ForeColor = Color.Gray
                End If

                If node.RowNodes.Count > 0 Then
                    SearchRecordName(node.RowNodes, isCallNode, localVariable) '2024-05-20 阿标 被调函数有多级节点时，将子级CallNode属性带入函数
                End If

                '如果为Call命令则添加被调用模块下内容
                If node.RowType = RowNode.RowTypeEnum.Flow AndAlso node.Command = "Call" Then
                    Dim moduleName As String = node.Parameters(0).Value
                    Dim varNames() As String = node.Parameters(1).Value.Split(":"c)
                    Dim varValues() As String = node.Parameters(2).Value.Split(":"c)

                    Dim variable As New Dictionary(Of String, String)
                    For i As Integer = 0 To varNames.Count - 1
                        variable.Add(varNames(i), varValues(i))
                    Next

                    Dim moduleNode As RowNode = GetModule(moduleName)
                    If moduleNode Is Nothing Then
                        MsgBox($"行号:{node.RowListIndex} 未找到可调用模块：{moduleName}")
                        Continue For
                    End If
                    SearchRecordName(moduleNode.RowNodes, True, variable)
                End If
            Next
        End Sub

        ''' <summary>
        ''' 更新测试模块入库
        ''' </summary>
        Private Sub UpdateTestModule(rowNodes As RowNodeCollection)
            _testModules.Clear()

            GetTestModule(_testModules, rowNodes)
        End Sub

        ''' <summary>
        ''' 获取执行行节点集合中测试模块入口，并存储至内部模块入口集合
        ''' </summary>
        ''' <param name="modules">存储测试模块入口集合</param>
        ''' <param name="nodes">行节点集合</param>
        Private Sub GetTestModule(modules As Dictionary(Of String, RowNode), nodes As RowNodeCollection)
            For Each node As RowNode In nodes
                If node.RowType = RowNode.RowTypeEnum.FixedModule OrElse node.RowType = RowNode.RowTypeEnum.Module Then
                    If String.IsNullOrWhiteSpace(node.Label) Then Continue For
                    If modules.ContainsKey(node.Label) Then Continue For
                    modules.Add(node.Label, node)
                End If

                If node.Label = $"{FixedModuleEnum.Custom}" Then
                    _customModules.Clear()
                    GetTestModule(_customModules, node.RowNodes)
                End If
            Next
        End Sub

        ''' <summary>
        ''' 获取固定模块节点
        ''' </summary>
        ''' <param name="name">固定模块名</param>
        ''' <returns></returns>
        Public Function GetFixedModule(name As FixedModuleEnum) As RowNode
            If _testModules.ContainsKey($"{name}") = False Then Return Nothing
            Return _testModules($"{name}")
        End Function

        ''' <summary>
        ''' 获取模块节点
        ''' </summary>
        ''' <param name="name">模块名</param>
        ''' <returns></returns>
        Public Function GetModule(name As String) As RowNode
            If _customModules.ContainsKey(name) Then
                Return _customModules(name)
            ElseIf _testModules.ContainsKey(name) Then
                Return _testModules(name)
            Else
                Return Nothing
            End If

            'If _testModules.ContainsKey(name) = False Then Return Nothing

            'Return _testModules(name)
        End Function

        Public Sub UpdateStepTestRecord()
            With _grd
                .AutoRedraw = False
                .AutoSize = True
                .Cols = ColNames.Max
                .Rows = 1
                .ExtendLastCol = True   '最后一列自动扩充
                .DisplayRowNumber = True    '首列显示数字

                For col As Integer = 0 To ColNames.Max - 1
                    .Cell(0, col).Text = [Enum].GetName(GetType(ColNames), col) '设置列名
                    .Column(col).CellType = _colType(col) '设置列型
                    .Column(col).Width = _colWidth(col) '设置列宽
                    If col = 3 Then 'Momo 2023-11-14 第三行文字居中
                        .Column(col).Alignment = AlignmentEnum.CenterCenter
                    End If
                Next


                .ForeColorComment = Color.Blue

                .FrozenCols = ColNames.Description '冻结列

                .Column(ColNames.Elapsed).Alignment = AlignmentEnum.RightCenter '设置对齐位置

                _nodeList.Clear()
                _rowList.Clear()
                _recodeRow.Clear()
                _callNodeList.Clear()
                If StationPlan IsNot Nothing Then
                    UpdateTestModule(StationPlan.RowNodes) '记录所有模块名

                    Dim mainNode As RowNode = GetFixedModule(FixedModuleEnum.Main)
                    SearchRecordName(mainNode.RowNodes) '添加Main模块下节点，遇见Call命令则展开被调用的模块
                End If

                .AutoRedraw = True
                .Refresh()
            End With
        End Sub


        ''' <summary>
        ''' 初始化记录表格
        ''' </summary>
        ''' <param name="plan">测试流程</param>
        Private Sub UpdateStepTestRecord(plan As StationTestPlan)
            With _grd
                .AutoRedraw = False
                .AutoSize = True
                .Cols = ColNames.Max
                .Rows = 1
                .ExtendLastCol = True   '最后一列自动扩充
                .DisplayRowNumber = True    '首列显示数字

                For col As Integer = 0 To ColNames.Max - 1
                    .Cell(0, col).Text = [Enum].GetName(GetType(ColNames), col) '设置列名
                    .Column(col).CellType = _colType(col) '设置列型
                    .Column(col).Width = _colWidth(col) '设置列宽
                Next
                .ForeColorComment = Color.Blue

                .FrozenCols = ColNames.Description '冻结列

                .Column(ColNames.Elapsed).Alignment = AlignmentEnum.RightCenter '设置对齐位置

                _nodeList.Clear()
                _rowList.Clear()
                _recodeRow.Clear()
                _callNodeList.Clear()
                If StationPlan IsNot Nothing Then
                    UpdateTestModule(StationPlan.RowNodes) '记录所有模块名

                    Dim mainNode As RowNode = GetFixedModule(FixedModuleEnum.Main)
                    SearchRecordName(mainNode.RowNodes) '添加Main模块下节点，遇见Call命令则展开被调用的模块
                End If

                .AutoRedraw = True
                .Refresh()
            End With
        End Sub

        Private _lastNode As RowNode

        ''' <summary>
        ''' 获取当前节点所在的记录行,0代表未找到对应节点
        ''' </summary>
        ''' <param name="node">当前测试节点</param>
        ''' <returns></returns>
        Public Function GetRowByNode(node As RowNode) As Integer
            Dim row As Integer = 0
            If _nodeList.ContainsKey(node) Then
                row = _nodeList(node)
            ElseIf _callNodeList.ContainsKey(node) Then
                If _callNodeUpdateCount.ContainsKey(node) Then
                    If _lastNode IsNot Nothing AndAlso _lastNode.RowListIndex <> node.RowListIndex AndAlso node.IsRetry = False Then
                        _callNodeUpdateCount(node) += 1
                        Console.WriteLine($"Node:{node.Description} Count:{_callNodeUpdateCount(node)}")
                    End If
                Else
                    _callNodeUpdateCount.Add(node, 0)
                    Console.WriteLine($"Node:{node.Description} Count:{_callNodeUpdateCount(node)}")
                End If

                row = _callNodeList(node)(_callNodeUpdateCount(node))
            End If

            _lastNode = node
            Return row
        End Function


        ''' <summary>
        ''' 反显当前测试节点所在的记录行
        ''' </summary>
        ''' <param name="node">当前测试节点</param>
        Public Sub UpdateTestRow(node As RowNode)
            Dim row As Integer = GetRowByNode(node)
            If row <= 0 Then Return

            If _grd.InvokeRequired Then '判断是否需要开委托
                _grd.Invoke(New Action(Of Integer)(Sub()
                                                       _grd.Range(row, 1, row, _grd.Cols - 1).SelectCells()
                                                   End Sub), New Object() {row})
            Else
                _grd.Range(row, 1, row, _grd.Cols - 1).SelectCells()
            End If
        End Sub


        ''' <summary>
        ''' 更新测试记录表格指定记录名的记录结果列内容
        ''' </summary>
        ''' <param name="node"></param>
        ''' <param name="recordValue"></param>
        Public Sub UpdateTestRecord(node As RowNode, recordValue As TestCommandReturn)
            If _grd.InvokeRequired Then '判断是否需要开委托
                _grd.Invoke(New Action(Of RowNode, TestCommandReturn)(AddressOf UpdateTestRecord), New Object() {node, recordValue})
                Return
            End If

            Dim row As Integer = GetRowByNode(node)
            If row <= 0 Then Return

            If recordValue.ExecuteResult Then
                _grd.Cell(row, ColNames.Result).ForeColor = Color.Green
            Else
                _grd.Cell(row, ColNames.Result).ForeColor = Color.Red
            End If

            _grd.Cell(row, ColNames.Elapsed).Text = recordValue.StepTimeSpan.TotalMilliseconds.ToString("N0")
            _grd.Cell(row, ColNames.Lower).Text = recordValue.LowerLimit
            _grd.Cell(row, ColNames.Upper).Text = recordValue.UpperLimit
            _grd.Cell(row, ColNames.Result).Text = recordValue.RecordValue

            ' _grd.Range(row, 1, row, _grd.Cols - 1).SelectCells()
            '_grd.Cell(row, ColNames.Description).EnsureVisible()
        End Sub

        ''' <summary>
        ''' 更新测试记录表格指定记录名的记录结果列内容
        ''' </summary>
        ''' <param name="recordName"></param>
        ''' <param name="recordValue"></param>
        Public Sub UpdateTestRecord(recordName As String, recordValue As TestCommandReturn)
            If _grd Is Nothing Then Return

            For row As Integer = 1 To _grd.Rows - 1
                If String.Compare(recordName, _grd.Cell(row, ColNames.Record).Text, True) <> 0 Then
                    Continue For
                End If

                If _grd.InvokeRequired Then '判断是否需要开委托
                    _grd.Invoke(New Action(Of String, TestCommandReturn)(AddressOf UpdateTestRecord), New Object() {recordName, recordValue})
                    Return
                End If

                If recordValue.ExecuteResult Then
                    _grd.Cell(row, ColNames.Result).ForeColor = Color.Green
                Else
                    _grd.Cell(row, ColNames.Result).ForeColor = Color.Red
                End If

                _grd.Cell(row, ColNames.Lower).Text = recordValue.LowerLimit
                _grd.Cell(row, ColNames.Upper).Text = recordValue.UpperLimit
                _grd.Cell(row, ColNames.Result).Text = recordValue.RecordValue
                _grd.Range(row, 1, row, _grd.Cols - 1).SelectCells()
                ' _grd.Cell(row, ColNames.Result).SetFocus()
            Next
        End Sub


        Public Sub ClearRecode()
            If _grd Is Nothing Then Return

            _lastNode = Nothing
            _callNodeUpdateCount.Clear()
            For row As Integer = 1 To _grd.Rows - 1
                _grd.Cell(row, ColNames.Elapsed).Text = ""

                _grd.Cell(row, ColNames.Result).Text = ""
                _grd.Cell(row, ColNames.Result).ForeColor = Color.Black
            Next
        End Sub


        ''' <summary>
        ''' 显示所有行
        ''' </summary>
        Public Sub ShowAllRows()
            '把隐藏的行显示
            For i As Integer = 1 To _grd.Rows - 1
                _grd.Row(i).Visible = True
            Next

        End Sub

        ''' <summary>
        ''' 屏蔽非记录行
        ''' </summary>
        Public Sub ShowRecordRows()
            '折叠所有的非记录的行
            For i As Integer = 1 To _grd.Rows - 1
                _grd.Row(i).Visible = _recodeRow.Contains(i)
            Next

        End Sub

    End Class
End Namespace