Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Text
Imports System.Threading
Imports System.Windows.Forms
Imports UTS_Core.DebugLog
Imports UTS_Core.UTSModule.DbConnect
Imports UTS_Core.UTSModule.DbTableModel.Customer
Imports UTS_Core.UTSModule.Production
Imports UTS_Core.UTSModule.Station
Imports UTS_Core.UTSModule.Station.StationTestPlan
Imports UTS_Core.UTSModule.Test.Command.SystemCommand
Imports UTS_Core.UTSModule.Test.Controls
Imports UTS_Core.UTSModule.Test.StatusMonitor
Imports UTS_Core.UTSModule.Test.StatusMonitor.TestStatusMonitor


Namespace UTSModule.Test
    Public Class FrmStationTest
        Implements IUtsTest
        Implements IProcessStation
        Implements IProductionLine

        Private _utsApp As UtsAppForm


        ''' <summary> 测试错误代码管理器</summary>
        Private _errCodeManager As ErrCodeManager

        ''' <summary>测试线程</summary>
        Private _testThread As Thread

        ''' <summary>测试站信息</summary>
        Public TestProcessStation As ProcessStation

        ''' <summary>测试记录表格</summary>
        Private _recordGrid As TestRecordGrid

#Region "UTS窗体公共模块"
        Public Sub ShowForm(parentControl As Control)
            FormBorderStyle = FormBorderStyle.None
            TopLevel = False
            Dock = DockStyle.Fill
            Parent = parentControl

            Show()
        End Sub

        ''' <summary>
        ''' 产线变化
        ''' </summary>
        Public Sub ProductionLineChanged() Implements IProductionLine.ProductionLineChanged
            'Todo:产线变化代码
            ApplicationLog.WriteInfoLog($"测试页面生产线变更中。")


            ApplicationLog.WriteInfoLog($"测试页面生产线变更完成。")
        End Sub

        ''' <summary>
        ''' 站位变化
        ''' </summary>

        Public Sub Station_Changed() Implements IProcessStation.StationChanged
            ApplicationLog.WriteInfoLog($"测试页面站位变更中，PN：{_utsApp.ProcessStation.ParentProject.Name} - SN:{_utsApp.ProcessStation.Name} - TP:{_utsApp.ProcessStation.Packet.Name}!")

            TestProcessStation = _utsApp.ProcessStation

            _tester.ProcessStation = TestProcessStation '绑定测试器的流程

            _recordGrid.StationPlan = CType(TestProcessStation.Packet.StationPlan, StationTestPlan)

            LblStation.Text = $"{TestProcessStation.ParentProject.Name} : {TestProcessStation.Name}"

            PicStepTip.Image = TestProcessStation.Packet.StationImage '重置提示图


            '初始化提示信息图执行类中耦合变量
            ShowTipImageExecutor.TipImageControl = PicStepTip
            ShowTipsExecutor.TipControl = LblTipString

            DbConnector.UtsCreateTestLogTableToLocal(TestProcessStation.ParentProject.Index, TestProcessStation.StationID) '创建本地记录表

            InitChartData(TestProcessStation.ParentProject.Index, TestProcessStation.StationID) '更新本地图表数据
            UpdateTestLogToCsv(_tester.GetFixedModule(FixedModuleEnum.Main).RowList.ToArray()) '更新CSV文件

            ApplicationLog.WriteInfoLog($"测试页面站位变更完成!")
        End Sub
#End Region

#Region "Form Event"

        Dim gRunFlag As Int16 = 0
        Private Sub FrmStationTest_Load(sender As Object, e As EventArgs) Handles Me.Load
            ApplicationLog.WriteInfoLog($"测试页面加载中。")

            '初始化UTS窗体信息,失败则关闭窗体
            If InitializeUtsApp() = False Then Return
            gRunFlag = 1

            '初始化错误代码
            _errCodeManager = ErrCodeManager.CreateManager()
            gRunFlag = 2

            '初始化窗体页面
            InitializeForm()
            gRunFlag = 3

            '初始化测试器
            InitTester()
            gRunFlag = 4

            AddHandler UtsKeyValueMonitor.UtsKeyDown, AddressOf UtsKeyDownCallback '按键检测
            AddHandler StationEditStatusMonitor.StationEditStatusChanged, AddressOf StationEditStatusChanged '流程编辑检测

            ApplicationLog.WriteInfoLog($"测试页面加载完成。")
            gRunFlag = 5

        End Sub


        Private Function InitializeUtsApp() As Boolean
            _utsApp = UtsAppForm.CreateSingleton()
            _utsApp.AddStatisticsObserver(Me)

            Try
                If _utsApp.IsInitialized = False Then
                    _utsApp.Initialize() 'Todo:可根据需要限定可选站位
                End If
            Catch ex As Exception
                ApplicationLog.WriteErrorLog($"初始化窗体失败,原因：{ex.Message}!")

                MsgBox($"初始化窗体失败,原因：{ex.Message}")
                Close()
                Return False
            End Try

            Return True
        End Function

        Private Sub InitializeForm()
            InitBarChart()

            InitPieChart()

            InitRecordGrid()
        End Sub


        Private Sub Btn_StartTest_Click(sender As Object, e As EventArgs) Handles BtnStartTest.Click
            Static waitStop As Boolean = False
            If waitStop = True Then Return
            waitStop = True
            StartTestEvent()
            waitStop = False
        End Sub


        Private Sub StationEditStatusChanged(sender As Object, e As StationEditStatusChangedEventArgs)
            If e.Status <> StationEditStatusMonitor.StationEditStatusEnum.Saved Then Return

            If GrdStepTestRecord.InvokeRequired Then '判断是否需要开委托
                GrdStepTestRecord.Invoke(New Action(Of Object, StationEditStatusChangedEventArgs)(AddressOf StationEditStatusChanged), New Object() {sender, e})
                Return
            End If

            _recordGrid.UpdateStepTestRecord()
        End Sub
#End Region

#Region "外部按键事件"
        Private Sub UtsKeyDownCallback(sender As Object, e As UtsKeyDownEventArgs)
            If BtnStartTest.InvokeRequired Then
                BtnStartTest.Invoke(New Action(Of UtsKeyValueMonitor.UtsKeyValueEnum)(AddressOf UpdateKey), New Object() {e.KeyValue})
            Else
                UpdateKey(e.KeyValue)
            End If
        End Sub

        Private Sub UpdateKey(key As UtsKeyValueMonitor.UtsKeyValueEnum)
            Static waitStop As Boolean = False
            If key = UtsKeyValueMonitor.UtsKeyValueEnum.Start Then
                If waitStop = True Then Return
                waitStop = True
                StartTestEvent()
                waitStop = False
            End If
        End Sub
#End Region

#Region "CSV测试记录"
        Private Sub UpdateTestLogToCsv(nodes() As RowNode)
            Dim dirPath As String = $"{Application.StartupPath}\LocalTestLog"
            Dim filePath As String = $"{dirPath}\TestLog_{Now:yyyyMMdd}.csv"

            If IO.Directory.Exists(dirPath) = False Then IO.Directory.CreateDirectory(dirPath)

            Dim str As New StringBuilder
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Start{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Load,{TestProcessStation.Packet.FileName}{vbCrLf}")

            Dim testItems As New StringBuilder
            Dim testSteps As New StringBuilder
            Dim testCmdTypes As New StringBuilder
            Dim testCmdNames As New StringBuilder

            Dim param1 As New StringBuilder
            Dim param2 As New StringBuilder
            Dim param3 As New StringBuilder
            Dim param4 As New StringBuilder
            Dim param5 As New StringBuilder
            Dim param6 As New StringBuilder
            Dim param7 As New StringBuilder
            Dim param8 As New StringBuilder

            For Each node As RowNode In nodes
                If String.IsNullOrWhiteSpace(node.RecordName) Then
                    Continue For
                End If

                testItems.Append(","c)
                testItems.Append(node.RecordName)

                testSteps.Append(","c)
                testSteps.Append(node.RowListIndex)

                testCmdTypes.Append(","c)
                testCmdTypes.Append(node.CommandType)

                testCmdNames.Append(","c)
                testCmdNames.Append(node.Command)

                param1.Append(","c)
                If node.Parameters.Count > 0 Then param1.Append(node.Parameters(0).Value)

                param2.Append(","c)
                If node.Parameters.Count > 1 Then param2.Append(node.Parameters(1).Value)

                param3.Append(","c)
                If node.Parameters.Count > 2 Then param3.Append(node.Parameters(2).Value)

                param4.Append(","c)
                If node.Parameters.Count > 3 Then param4.Append(node.Parameters(3).Value)

                param5.Append(","c)
                If node.Parameters.Count > 4 Then param5.Append(node.Parameters(4).Value)

                param6.Append(","c)
                If node.Parameters.Count > 5 Then param6.Append(node.Parameters(5).Value)

                param7.Append(","c)
                If node.Parameters.Count > 6 Then param7.Append(node.Parameters(6).Value)

                param8.Append(","c)
                If node.Parameters.Count > 7 Then param8.Append(node.Parameters(7).Value)
            Next

            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},TestStep,{testSteps}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},TestItem,{testItems}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},CmdType,{testCmdTypes}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Command,{testCmdNames}{vbCrLf}")

            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_1,{param1}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_2,{param2}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_3,{param3}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_4,{param4}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_5,{param5}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_6,{param6}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_7,{param7}{vbCrLf}")
            str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_8,{param8}{vbCrLf}")

            Try
                IO.File.AppendAllText(filePath, str.ToString())
            Catch ex As Exception
                ApplicationLog.WriteErrorLog($"更新CSV文件失败,原因：{ex.Message}")
                UtsMsgBox.ShowDialog($"更新CSV文件失败,原因：{ex.Message}")
            End Try
        End Sub


        ''' <summary>
        '''  存储单笔测试记录至CSV文件
        ''' </summary>
        Private Sub SaveTestLogToCsv(result As TestResult)
            Dim dirPath As String = $"{Application.StartupPath}\LocalTestLog"
            Dim filePath As String = $"{dirPath}\TestLog_{Now:yyyyMMdd}.csv"

            '设置写入内容
            Dim str As New StringBuilder
            str.Append($"{result.DUT_SN},{Now:yyyyMMdd},{Now:HH:mm:ss},{result.TestResult}")
            If result.FailSteps.Count > 0 Then
                str.Append($",{result.FailSteps(0).RowListIndex}")
            Else
                str.Append($",")
            End If
            str.Append($",{result.DUT_SN}")
            For Each keyValuePair As KeyValuePair(Of String, String) In result.CustomRecord
                str.Append($",{keyValuePair.Value}")
            Next
            str.Append(vbCrLf)

            Try
                IO.File.AppendAllText(filePath, str.ToString())
            Catch ex As Exception
                ApplicationLog.WriteErrorLog($"保存测试结果至CSV文件失败：{ex.Message}")
                UtsMsgBox.ShowDialog($"保存测试结果至CSV文件失败:{ex.Message}")
            End Try
        End Sub
#End Region

#Region "统一查询图表数据"
        Private ReadOnly _pieResults As New List(Of PieChartResult)

        Private ReadOnly _barResults As New List(Of BarChartResult)

        Private ReadOnly _pointResults As New List(Of PointChartResult)

        Private Sub InitChartData(pid As Integer, sid As Integer)
            ApplicationLog.WriteInfoLog($"测试页面统计图表绘制中。")

            _pieResults.Clear()
            _barResults.Clear()
            _pointResults.Clear()

            Dim dtTable As DataTable = DbConnector.GetTodayTestResult(pid, sid)

            Dim result As New TestResult
            For Each row As DataRow In dtTable.Rows
                Dim a As String = row($"{TestLogTable.ColNames.StartTime}").ToString()

                If Date.TryParse(a, result.StartTime) = False Then Continue For

                Dim c As String = row($"{TestLogTable.ColNames.TestResult}").ToString()
                If String.Compare(c, "1") = 0 Then
                    result.TestResult = TestResult.TestResultEnum.Pass
                Else
                    result.TestResult = TestResult.TestResultEnum.Fail
                End If

                result.DUT_SN = row($"{TestLogTable.ColNames.DUT_SN}").ToString()
                If String.IsNullOrWhiteSpace(result.DUT_SN) Then Continue For

                result.ErrCode = row($"{TestLogTable.ColNames.ErrCode}").ToString()

                AddPieChart(result)

                AddBarChart(result)

                AddPointChart(result)
            Next

            RedrawPointChart()

            ApplicationLog.WriteInfoLog($"测试页面统计图表绘制完成。")
        End Sub
#End Region

#Region "良率统计"
        Private Sub InitPieChart()
            ChartPie.Header.Text = "良率统计" '标题
            ChartPie.Header.Visible = False '隐藏标题

            ChartPie.Legend.Alignment = Steema.TeeChart.LegendAlignments.Right
            ChartPie.Legend.Font.Brush.Color = Color.Gray
            ChartPie.Legend.Font.SizeFloat = 8.0!
            ChartPie.Legend.Transparent = True

            ChartPie.Walls.Back.Visible = False
            ChartPie.Walls.Back.Transparent = True

            '  TcPie.ExplodeBiggest = 10 '最大饼块与饼图分割位置
            TcPie.ExplodedSlice.Add(10)
            TcPie.Circled = True '饼图圆形
            TcPie.Transparency = 10
            TcPie.UniqueCustomRadius = True
            TcPie.UseExtendedNumRange = False

            TcPie.Frame.Circled = True

            TcPie.Pen.Visible = False '取消绘制边框

            TcPie.Marks.Font.Brush.Color = Color.White '标签内容字体颜色
            TcPie.Marks.Font.Name = $"Consolas" '标签内容字体名
            TcPie.Marks.Shadow.Visible = False
            TcPie.Marks.Transparent = True
            TcPie.Marks.Visible = True
            TcPie.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Percent '百分比
            TcPie.MarksPie.InsideSlice = True

            TcPie.YValues.Order = Steema.TeeChart.Styles.ValueListOrder.Descending '倒序排序
        End Sub


        Private Sub AddPieChart(result As TestResult)
            Dim code As String
            Dim msg As String
            Dim color As Color

            If result.TestResult = TestResult.TestResultEnum.Pass Then
                code = "PASS"
                msg = "测试通过"
                color = _errCodeManager("9002").Color
            Else
                If _errCodeManager.IndexOf(result.ErrCode) <> -1 Then
                    code = result.ErrCode
                    msg = _errCodeManager(result.ErrCode).Msg
                    color = _errCodeManager(result.ErrCode).Color
                Else
                    code = "9001"
                    msg = _errCodeManager(code).Msg
                    color = _errCodeManager(code).Color
                End If
            End If


            Dim addPie As Boolean = True
            For i As Integer = 0 To _pieResults.Count - 1
                If _pieResults(i).CodeEqual(code) Then
                    _pieResults(i).AddResult()
                    addPie = False
                    Exit For
                End If
            Next

            If addPie Then
                Dim pieResult As New PieChartResult(code, msg, color)
                pieResult.AddResult()
                _pieResults.Add(pieResult)
            End If

            ReDrawPie()
        End Sub

        Private Sub ReDrawPie()
            TcPie.BeginUpdate()
            TcPie.Clear()

            For i As Integer = 0 To _pieResults.Count - 1
                TcPie.Add(_pieResults(i).Count, _pieResults(i).Code & " : " & _pieResults(i).Msg, _pieResults(i).Color)
            Next

            TcPie.EndUpdate()
        End Sub


        Class PieChartResult
            Sub New(code As String, msg As String, color As Color)
                Me.Code = code
                Me.Msg = msg
                Me.Color = color
            End Sub


            Property Code() As String

            Property Msg() As String

            Property Color() As Color

            Property Count() As Integer

            Public Function CodeEqual(srcCode As String) As Boolean
                If String.Compare(Code, srcCode) = 0 Then
                    Return True
                End If

                Return False
            End Function

            Public Sub AddResult()
                Count += 1
            End Sub
        End Class
#End Region

#Region "图表生产统计"
        Private Sub InitBarChart()
            ChartBar.Header.Text = "生产统计" '标题
            ChartBar.Header.Visible = False '隐藏标题

            ChartBar.Legend.Transparent = True '刻印说明
            ChartBar.Legend.Alignment = Steema.TeeChart.LegendAlignments.Top

            TcBarPass.Pen.Visible = False
            TcBarPass.Brush.Color = _errCodeManager("9002").Color
            TcBarPass.Brush.Transparency = 40
            TcBarPass.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked '与其他柱状图并列显示
            TcBarPass.Marks.Transparent = True '标记提示边框透明
            TcBarPass.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Value '提示标签类型为数值
            TcBarPass.Marks.AutoPosition = False
            TcBarPass.MarksLocation = Steema.TeeChart.Styles.MarksLocation.Start '标签文本在柱状图上面显示
            TcBarPass.Legend.Text = "Pass"

            TcBarFail.Pen.Visible = False
            TcBarFail.Brush.Color = _errCodeManager("9003").Color
            TcBarFail.Brush.Transparency = 40
            TcBarFail.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked '与其他柱状图并列显示
            TcBarFail.Marks.Transparent = True '标记提示边框透明
            TcBarFail.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Value '提示标签类型为数值
            TcBarFail.Marks.AutoPosition = False

            TcBarFail.MarksLocation = Steema.TeeChart.Styles.MarksLocation.Start '标签文本在柱状图上面显示
            TcBarFail.Legend.Text = "Fail"
        End Sub


        Dim gAllCount As Integer = 0
        Dim gPassCount As Integer = 0
        Dim gFailCount As Integer = 0
        Private Sub AddBarChart(result As TestResult)
            '填充内存
            Dim addBar As Boolean
            Dim tmp As BarChartResult

            If _barResults.Count > 0 Then
                If _barResults(_barResults.Count - 1).TimeEqual(result.StartTime) Then
                    tmp = _barResults(_barResults.Count - 1)
                Else
                    If result.StartTime.Hour = 0 Then
                        _barResults.Clear() '过零点则清空
                        TcBarPass.Clear()
                        TcBarFail.Clear()
                    End If

                    tmp = New BarChartResult(result.StartTime)
                    _barResults.Add(tmp)

                    If _barResults.Count > 8 Then '超过八个小时,移除前一小时数据
                        _barResults.RemoveAt(0)
                        addBar = False
                    Else
                        addBar = True
                    End If
                End If
            Else
                tmp = New BarChartResult(result.StartTime)
                _barResults.Add(tmp)
                addBar = True
            End If
            tmp.AddResult(result.TestResult = TestResult.TestResultEnum.Pass)

            '填充图表
            If addBar Then
                TcBarPass.Add(tmp.RecordTime, tmp.PassCount)
                TcBarFail.Add(tmp.RecordTime, tmp.FailCount)
            Else
                RedrawBarChart()
            End If

            '更新测试计数 Momo 2023-11-14
            gAllCount += 1
            If result.TestResult = TestResult.TestResultEnum.Pass Then
                gPassCount += 1
            Else
                gFailCount += 1
            End If

            Try
                TssLblTestCount.Text = "Count:" & gAllCount
                TssLblPassCount.Text = "Pass:" & gPassCount
                TssLblFailCount.Text = "Fail:" & gFailCount
            Catch ex As Exception

            End Try

        End Sub

        Private Sub RedrawBarChart()
            TcBarPass.Clear()
            TcBarFail.Clear()
            For i As Integer = 0 To _barResults.Count - 1
                TcBarPass.Add(_barResults(i).RecordTime, _barResults(i).PassCount)
                TcBarFail.Add(_barResults(i).RecordTime, _barResults(i).FailCount)
            Next
        End Sub

        Class BarChartResult
            Sub New(time As Date)
                RecordTime = New DateTime(time.Year, time.Month, time.Day, time.Hour, 0, 0)
                PassCount = 0
                FailCount = 0
                AllCount = 0
            End Sub

            Property RecordTime() As DateTime

            Property PassCount As Integer

            Property FailCount As Integer

            Property AllCount As Integer



            Public Function TimeEqual(srcTime As DateTime) As Boolean
                If RecordTime.Day = srcTime.Day AndAlso RecordTime.Hour = srcTime.Hour Then
                    Return True
                End If

                Return False
            End Function


            Public Sub AddResult(passed As Boolean)
                If passed Then
                    PassCount += 1
                Else
                    FailCount += 1
                End If

                AllCount += 1


            End Sub

        End Class

#End Region

#Region "点阵生产统计"

        ''' <summary>当前绘制图形宽度</summary>
        Private _drawW As Integer

        ''' <summary>当前绘制图形坐标点X</summary>
        Private _drawX As Integer

        ''' <summary>当前绘制图形坐标点Y</summary>
        Private _drawY As Integer

        ''' <summary>当前绘制图形单行最大上限</summary>
        Private _drawLineMaxCount As Integer

        ''' <summary>
        ''' 添加绘制测试结果
        ''' </summary>
        ''' <param name="result"></param>
        Private Sub AddPointChart(result As TestResult)
            Dim a As New PointChartResult With {.BarCode = result.DUT_SN}
            If result.TestResult = TestResult.TestResultEnum.Pass Then
                a.Result = True
                a.Color = _errCodeManager("9002").Color
            Else
                a.Result = False
                If _errCodeManager.IndexOf(result.ErrCode) <> -1 Then
                    a.Color = _errCodeManager(result.ErrCode).Color
                Else
                    a.Color = _errCodeManager("9001").Color
                End If
            End If
            _pointResults.Add(a)

            DrawPointChart(_pointResults.Count - 1) '从0开始
        End Sub


        Private Sub DrawPointChart(index As Integer)
            If PnlPoint.InvokeRequired Then
                PnlPoint.Invoke(New Action(Of Integer)(AddressOf DrawPointChart), New Object() {index})
                Return
            End If

            Using g As Graphics = PnlPoint.CreateGraphics()
                g.SmoothingMode = SmoothingMode.HighQuality '抗锯齿
                If index = 0 Then
                    ResetPointChart()
                ElseIf index Mod _drawLineMaxCount = 0 Then
                    _drawY += _drawW + 2
                    _drawX = 2
                Else
                    _drawX += _drawW + 2
                End If

                g.FillEllipse(New SolidBrush(_pointResults(index).Color), New Rectangle(_drawX, _drawY, _drawW, _drawW))
            End Using
        End Sub

        Private Sub ResetPointChart()
            _drawW = 6
            _drawX = 2
            _drawY = 2
            _drawLineMaxCount = PnlPoint.Width \ (2 + _drawW)
        End Sub

        Private Sub RedrawPointChart()
            Using g As Graphics = PnlPoint.CreateGraphics()
                g.SmoothingMode = SmoothingMode.HighQuality '抗锯齿
                For index As Integer = 0 To _pointResults.Count - 1
                    If index = 0 Then
                        ResetPointChart()
                    ElseIf index Mod _drawLineMaxCount = 0 Then
                        _drawY += _drawW + 2
                        _drawX = 2
                    Else
                        _drawX += _drawW + 2
                    End If

                    g.FillEllipse(New SolidBrush(_pointResults(index).Color), New Rectangle(_drawX, _drawY, _drawW, _drawW))
                Next
            End Using
        End Sub

        Private Sub PnlProduct_SizeChanged(sender As Object, e As EventArgs) Handles PnlPoint.SizeChanged

        End Sub

        Class PointChartResult
            Property BarCode() As String


            Property Result() As Boolean

            Property Color() As Color
        End Class

        Private Sub PnlPoint_Paint(sender As Object, e As PaintEventArgs) Handles PnlPoint.Paint
            RedrawPointChart()
        End Sub

#End Region

#Region "测试执行"

        Private Sub StartTestEvent()
            '检测
            If TestStatus = TestStatusEnum.Testing Then
                If UtsMsgBox.ShowDialog("当前已处于测试状态中,是否结束测试！", UtsMsgBox.UtsMsgBoxTypeEnum.YesNo, "测试已开启") = DialogResult.OK Then
                    StopTest()
                End If
                Return
            End If

            If TestProcessStation Is Nothing Then
                UtsMsgBox.ShowDialog("请选择测试站再尝试进行测试!")
                Return
            End If

            If CheckValidDate(TestProcessStation.Packet.ValidDate) = False Then
                UtsMsgBox.ShowDialog("测试功能已超过使用期限,请联系管理员！")
                Return
            End If


            If _testThread IsNot Nothing AndAlso _testThread.IsAlive Then
                UtsMsgBox.ShowDialog("测试线程未完全退出，请稍后开始测试！")
                Return
            End If

            StartTest() '开始测试
        End Sub

        ''' <summary>
        ''' 校验测试流程有效日期
        ''' </summary>
        ''' <returns></returns>
        Private Function CheckValidDate(validDate As Date) As Boolean
            Return Now.CompareTo(validDate) < 0
        End Function

        ''' <summary>
        ''' 开始测试
        ''' </summary>
        Private Sub StartTest()
            _testThread = New Thread(AddressOf _tester.StartTest)
            _testThread.Start() '开启测试线程
        End Sub


        ''' <summary>
        ''' 终止测试
        ''' </summary>
        Private Sub StopTest()
            _tester.ExitTest()
        End Sub

#End Region

#Region "统一测试模块"
        Private _tester As UtsTester

        Private Sub InitTester()
            ApplicationLog.WriteInfoLog($"测试器初始化中。")
            _tester = UtsTester.CreateTester()

            '_tester.TestFailMode = UtsTester.TestFailModeEnum.StepFail

            AddHandler _tester.TestStart, AddressOf IUtsTest_TestStart
            AddHandler _tester.TestPass, AddressOf IUtsTest_TestPass
            AddHandler _tester.TestFail, AddressOf IUtsTest_TestFail
            AddHandler _tester.TestPause, AddressOf IUtsTest_TestPause
            AddHandler _tester.TestEnd, AddressOf IUtsTest_TestEnd

            AddHandler _tester.TestStatusChanged, AddressOf IUtsTest_TestStatusChanged

            AddHandler _tester.TestNodeChanged, AddressOf IUtsTest_TestNodeChanged
            AddHandler _tester.TestNodeCompleted, AddressOf IUtsTest_TestNodeCompleted
            AddHandler _tester.TestNodeResultChanged, AddressOf IUtsTest_TestNodeResultChanged

            AddHandler _tester.TestProgressChanged, AddressOf IUtsTest_TestProgressChanged
            AddHandler _tester.RetryProgressChanged, AddressOf IUtsTest_RetryProgressChanged

            AddHandler _tester.TestTimeChanged, AddressOf IUtsTest_TestTimeChanged

            AddHandler StationEditStatusMonitor.StationEditStatusChanged, AddressOf _tester.StationEditStatusChanged

            ApplicationLog.WriteInfoLog($"测试器初始化完成。")
        End Sub

        Private Sub IUtsTest_TestStart(sender As Object, e As EventArgs) Implements IUtsTest.TestStart
            If _tester.DebugMode Then Return
            If PicStepTip.InvokeRequired Then '判断是否需要开委托
                PicStepTip.Invoke(New Action(Of Object, EventArgs)(AddressOf IUtsTest_TestStart), New Object() {sender, e})
                Return
            End If

            PicStepTip.Image = TestProcessStation.Packet.StationImage '重置提示图
            _recordGrid.ClearRecode() '清空测试记录项

            ApplicationLog.WriteInfoLog($"测试页面测试开始。")
        End Sub

        Private Sub IUtsTest_TestPass(sender As Object, e As EventArgs) Implements IUtsTest.TestPass
            If _tester.DebugMode Then Return
            ApplicationLog.WriteInfoLog($"测试页面测试成功。")
        End Sub

        Private Sub IUtsTest_TestFail(sender As Object, e As TestFailEventArgs) Implements IUtsTest.TestFail
            If _tester.DebugMode Then Return '调试模式不处理
            UpdateTestNode(e.Node)
            ApplicationLog.WriteInfoLog($"测试页面测试失败。")
        End Sub

        Private Sub IUtsTest_TestPause(sender As Object, e As TestPauseEventArgs) Implements IUtsTest.TestPause
            If _tester.DebugMode Then Return '调试模式不处理
            UpdateTestNode(e.Node)
            ApplicationLog.WriteInfoLog($"测试页面测试暂停。")
        End Sub

        Private Sub IUtsTest_TestEnd(sender As Object, e As TestEndEventArgs) Implements IUtsTest.TestEnd
            If _tester.DebugMode Then Return '调试模式不处理

            If String.IsNullOrWhiteSpace(e.TestResult.DUT_SN) Then
                ApplicationLog.WriteWarningLog($"测试页面测试结束,无SN号不予入库。")
                Return
            End If

            If e.TestResult.DUT_SN.Length > 32 Then
                ApplicationLog.WriteWarningLog($"测试页面测试结束,过长的SN号[{e.TestResult.DUT_SN}]不予入库。")
                MsgBox($"当前SN号[{e.TestResult.DUT_SN}]超过设定长度上限32,不予录入数据库。")
                Return
            End If


            ApplicationLog.WriteInfoLog($"测试页面测试结束处理中,SN:{e.TestResult.DUT_SN},Result:{e.TestResult.TestResult}。")

            SaveTestLogToCsv(e.TestResult) '保存至CSV
            SaveTestLogToDatabase(e.TestResult) '存储数据至数据库

            AddBarChart(e.TestResult) '当前时测试总数绘制至图表
            AddPointChart(e.TestResult) '测试结果绘制至点阵图
            AddPieChart(e.TestResult) '测试结果绘制至饼状图


            ApplicationLog.WriteInfoLog($"测试页面测试结束。")
        End Sub

        ''' <summary>
        '''  存储单笔测试记录至数据库
        ''' </summary>
        Private Sub SaveTestLogToDatabase(result As TestResult)
            If String.IsNullOrWhiteSpace(result.DUT_SN) Then Return '无SN不处理
            Try
                Dim tbName As String = TestLogTable.TableName(TestProcessStation.ParentProject.Index, TestProcessStation.StationID)
                DbConnector.SaveTestLog(tbName, TestProcessStation, result)
            Catch ex As Exception
                ApplicationLog.WriteErrorLog($"保存测试结果至数据库失败：{ex.Message}")
                UtsMsgBox.ShowDialog($"保存测试结果至数据库失败:{ex.Message}")
            End Try
        End Sub


        Private Sub IUtsTest_TestNodeChanged(sender As Object, e As TestNodeChangedEventArgs) Implements IUtsTest.TestNodeChanged
            If _tester.DebugMode Then Return
            UpdateTestNode(e.Node)
        End Sub

        Private Sub UpdateTestNode(node As RowNode)
            If _tester.DebugMode Then Return
            If _tester.TestFiexdModule <> FixedModuleEnum.Main Then Return
            If node.Action = False Then Return

            If LblTestStep.InvokeRequired Then '判断是否需要开委托
                LblTestStep.Invoke(New Action(Of RowNode)(AddressOf UpdateTestNode), New Object() {node})
                Return
            End If

            LblTestStep.Text = $"Step : [{node.RowListIndex}] - [{_recordGrid.GetRowByNode(node)}]"
            LblStepTip.Text = $"[{node.RowListIndex}]-{node.ParentNode.Label}:{node.Description}"

            _recordGrid.UpdateTestRow(node)
        End Sub

        Public Sub IUtsTest_TestNodeCompleted(sender As Object, e As TestNodeCompletedEventArgs) Implements IUtsTest.TestNodeCompleted
            If _tester.DebugMode Then Return
            If _tester.TestFiexdModule <> FixedModuleEnum.Main Then Return

            _recordGrid.UpdateTestRecord(e.Node, e.TestReturn)
        End Sub

        Public Sub IUtsTest_TestNodeResultChanged(sender As Object, e As TestNodeResultChangedEventArgs) Implements IUtsTest.TestNodeResultChanged
            If _tester.DebugMode Then Return
            If _tester.TestFiexdModule <> FixedModuleEnum.Main Then Return

            _recordGrid.UpdateTestRecord(e.Node, e.TestReturn)
        End Sub

        Public Sub IUtsTest_TestStatusChanged(sender As Object, e As TestStatusChangedEventArgs) Implements IUtsTest.TestStatusChanged
            If _tester.DebugMode Then Return
            UpdateTestStatus(e.Status)
        End Sub

        ''' <summary>
        ''' 根据测试状态,更新界面UI显示
        ''' </summary>
        ''' <param name="status"></param>
        Private Sub UpdateTestStatus(status As TestStatusEnum)
            If _tester.DebugMode Then Return
            If LblTestStatus.InvokeRequired Then '判断是否需要开委托
                LblTestStatus.Invoke(New Action(Of TestStatusEnum)(AddressOf UpdateTestStatus), New Object() {status})
                Return
            End If

            Select Case status
                Case TestStatusEnum.WaitForTest
                    LblTestStatus.ForeColor = _errCodeManager("9002").Color
                    LblTestStatus.Text = $"Wait"

                    ApplicationLog.WriteInfoLog($"测试页面测试状态变更,等待测试。")
                Case TestStatusEnum.Testing
                    LblTestStatus.ForeColor = _errCodeManager("9004").Color
                    LblTestStatus.Text = $"Testing"

                    ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试中。")
                Case TestStatusEnum.TestPass
                    LblTestStatus.ForeColor = _errCodeManager("9002").Color
                    LblTestStatus.Text = $"Pass"

                    ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试成功。")
                Case TestStatusEnum.TestFail
                    LblTestStatus.ForeColor = _errCodeManager("9003").Color
                    LblTestStatus.Text = $"Fail"

                    ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试失败。")
                Case TestStatusEnum.DeviceError
                    LblTestStatus.ForeColor = _errCodeManager("9003").Color
                    LblTestStatus.Text = $"Error"

                    ApplicationLog.WriteErrorLog($"测试页面测试状态变更,设备错误。")
                Case Else
                    Console.WriteLine($"测试页面测试状态变更,未知状态:{status}。")

                    ApplicationLog.WriteErrorLog($"测试页面测试状态变更,未知状态:{status}。")
            End Select

            LblTestStep.ForeColor = LblTestStatus.ForeColor
            LblStepTip.ForeColor = LblTestStatus.ForeColor

            If status = TestStatusEnum.Testing Then
                BtnStartTest.Text = $"Stop(&S)" '更新测试按键
                BtnStartTest.ForeColor = Color.OrangeRed
            Else
                BtnStartTest.Text = $"Start(&S)" '更新测试按键
                BtnStartTest.ForeColor = Color.Green
            End If
        End Sub

        Private Sub IUtsTest_TestTimeChanged(sender As Object, e As TestTimeEventArgs) Implements IUtsTest.TestTimeChanged
            If _tester.DebugMode Then Return
            UpdateTestTime(e.TimeElapsed)
        End Sub

        ''' <summary>
        ''' 更新测试时间
        ''' </summary>
        ''' <param name="elapsed"></param>
        Private Sub UpdateTestTime(elapsed As TimeSpan)
            If StuState.InvokeRequired Then '判断是否需要开委托
                StuState.Invoke(New Action(Of TimeSpan)(AddressOf UpdateTestTime), New Object() {elapsed})
                Return
            End If

            TssLblTestTime.Text = $"Time：{elapsed.Hours:D2}:{elapsed.Minutes:D2}:{elapsed.Seconds:D2}:{elapsed.Milliseconds:D3}"
        End Sub

        Private Sub IUtsTest_TestProgressChanged(sender As Object, e As TestProgressChangedEventArgs) Implements IUtsTest.TestProgressChanged
            If _tester.DebugMode Then Return
            UpdateTestProgress(CInt(e.Percent))
        End Sub

        Private Sub UpdateTestProgress(progress As Integer)
            Try
                If _tester.DebugMode Then Return
                If PrgStepTip.InvokeRequired Then '判断是否需要开委托
                    PrgStepTip.Invoke(New Action(Of Integer)(AddressOf UpdateTestProgress), New Object() {progress})
                    Return
                End If
                If progress < TssBarTestProgress.Minimum Then progress = TssBarTestProgress.Minimum
                If progress > TssBarTestProgress.Maximum Then progress = TssBarTestProgress.Maximum
                TssBarTestProgress.Value = progress
            Catch ex As Exception

            End Try

        End Sub

        Private Sub IUtsTest_RetryProgressChanged(sender As Object, e As TestProgressChangedEventArgs) Implements IUtsTest.RetryProgressChanged
            If _tester.DebugMode Then Return
            UpdateRetryProgress(CInt(e.Percent))
        End Sub

        Private Sub UpdateRetryProgress(progress As Integer)
            If _tester.DebugMode Then Return
            If PrgStepTip.InvokeRequired Then '判断是否需要开委托
                PrgStepTip.Invoke(New Action(Of Integer)(AddressOf UpdateRetryProgress), New Object() {progress})
                Return
            End If

            PrgStepTip.Value = progress
        End Sub


        Private Sub IUtsTest_TestCountChanged(sender As Object, e As TestCountChangedEventArgs) Implements IUtsTest.TestCountChanged
            If _tester.DebugMode Then Return
            UpdateTestCount(e.PassCount, e.FailCount)
        End Sub

        Private Sub UpdateTestCount(pass As Integer, fail As Integer)
            If StuState.InvokeRequired Then '判断是否需要开委托
                StuState.Invoke(New Action(Of Integer, Integer)(AddressOf UpdateTestCount), New Object() {pass, fail})
                Return
            End If

            TssLblFailCount.Text = $"Fail：{fail}"
            TssLblPassCount.Text = $"Pass：{pass}"
            TssLblTestCount.Text = $"Count：{pass + fail}"
        End Sub
#End Region

#Region "表格相关操作"
        Private Sub InitRecordGrid()
            _recordGrid = New TestRecordGrid() With {.Grid = GrdStepTestRecord}
        End Sub


        Private Sub TsmiShowAllRows_Click(sender As Object, e As EventArgs) Handles TsmiShowAllRows.Click
            _recordGrid.ShowAllRows()
        End Sub

        Private Sub TsmiShowRecordRows_Click(sender As Object, e As EventArgs) Handles TsmiShowRecordRows.Click
            _recordGrid.ShowRecordRows()
        End Sub

        Private Sub TsmiTestSetupNode_Click(sender As Object, e As EventArgs) Handles TsmiTestSetupNode.Click
            If _tester.ExecuteFixedModule(FixedModuleEnum.Setup).ExecuteResult Then
                UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Setup} 模块执行完成！")
            Else
                UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Setup} 模块执行失败！")
            End If
        End Sub

        Private Sub TsmiTestCleanupNode_Click(sender As Object, e As EventArgs) Handles TsmiTestCleanupNode.Click
            If _tester.ExecuteFixedModule(FixedModuleEnum.Cleanup).ExecuteResult Then
                UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Cleanup} 模块执行完成！")
            Else
                UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Cleanup} 模块执行失败！")
            End If
        End Sub

        Private Sub TsmiRetryTestNode_Click(sender As Object, e As EventArgs) Handles TsmiTestNode.Click
            Dim node As RowNode = _recordGrid.ActiveNode
            If node Is Nothing Then Return

            _tester.ExecutePlan(node, Nothing)
        End Sub

        Private Sub TsmiStartTestWithNode_Click(sender As Object, e As EventArgs) Handles TsmiStartTestWithNode.Click
            Dim node As RowNode = _recordGrid.ActiveNode
            If node Is Nothing Then Return

            While node IsNot Nothing
                _tester.ExecutePlan(node, Nothing)

                If node.NextNode Is Nothing Then
                    If node.RowLever = 1 Then Exit While
                    node = node.ParentNode
                Else
                    node = node.NextNode
                End If
            End While
        End Sub

        Public Sub SetSpcSplitterDistance(Distance As Integer)
            SpcMain.SplitterDistance = Distance
        End Sub

        Public Function GetSpcSplitterDistance() As Integer
            Return SpcMain.SplitterDistance
        End Function

#End Region

    End Class
End Namespace