Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.Windows.Forms
Imports UTS_Core.UTSModule.DbConnect
Imports UTS_Core.UTSModule.DbTableModel.Customer
Imports UTS_Core.UTSModule.Login
Imports UTS_Core.UTSModule.Production
Imports UTS_Core.UTSModule.Service
Imports UTS_Core.UTSModule.Station
Imports UTS_Core.UTSModule.Test
Imports UTS_Core.UTSModule.Test.StatusMonitor


Namespace UTSModule
    ''' <summary>
    '''UTS系列App与UtsCore交互为避免重复书写产生的中间类
    ''' </summary>
    Public Class UtsAppForm
        Implements IDisposable

        ''' <summary>本地服务索引</summary>
        Private _serviceIndex As Integer

        ''' <summary>本地服务角色,0客户端，1服务器</summary>
        Private _serviceRoles As Integer

        ''' <summary>本地服务别名</summary>
        Private _serviceAlias As String

        ''' <summary>本地服务组名（子网名）</summary>
        Private _serviceGroup As String

        ''' <summary>软件名称</summary>
        Private _appName As String

        ''' <summary>软件版本</summary>
        Private _appVersion As String

        ''' <summary>测试记录表名</summary>
        Private _testLogTableName As String

        ''' <summary>登录用户信息</summary>
        Private _userInfo As UserInfo

        ''' <summary>鉴权文件信息</summary>
        Private _license As License.License

        ''' <summary>当前选择站位信息</summary>
        Private _processStation As ProcessStation

        ''' <summary>测试结果内容</summary>
        Private ReadOnly _testResult As TestResult

        ''' <summary>软件注册器</summary>
        Private _register As AppRegister

        ''' <summary>服务通讯TCP客户端</summary>
        Private _tcpClient As TcpClient

        ''' <summary>是否释放当前类</summary>
        Private _disposedValue As Boolean

        ''' <summary>站位观察者集合</summary>
        Private ReadOnly _observerList As List(Of IProcessStation)

        ''' <summary>当前软件所属站位类型,None则无类型</summary>
        Private _stationType As ProcessStation.StationTypeEnum

        ''' <summary>UTS软件单例对象</summary>
        Private Shared _utsApp As UtsAppForm

        ''' <summary>UTS软件单例对象初始化锁</summary>
        Private Shared InitLock As New Object

        'CZH 2023-05-19  增加站位列表集
        Public projectInfo As Project.ProjectInfo
        ''' <summary>
        ''' 创建单例对象
        ''' </summary>
        ''' <returns></returns>
        Public Shared Function CreateSingleton() As UtsAppForm
            If _utsApp IsNot Nothing Then
                Return _utsApp
            End If

            SyncLock InitLock
                Thread.MemoryBarrier()
                If _utsApp Is Nothing Then
                    _utsApp = New UtsAppForm
                End If
            End SyncLock

            Return _utsApp
        End Function


        Private Sub New()
            _disposedValue = False

            _testLogTableName = String.Empty

            _testResult = New TestResult()

            _observerList = New List(Of IProcessStation)()

            ShowUnSearchOrderIDTip = True

            SaveUnSearchOrderIDLog = False

            IsInitialized = False
        End Sub

        ''' <summary>
        ''' 添加站位修改观察者,唯一添加
        ''' </summary>
        ''' <param name="observer"></param>
        Public Sub AddStatisticsObserver(observer As IProcessStation)
            If _observerList.Contains(observer) = False Then _observerList.Add(observer)
        End Sub

        ''' <summary>
        ''' 移除站位修改观察者
        ''' </summary>
        ''' <param name="observer"></param>
        Public Sub RemoveStatisticsObserver(observer As IProcessStation)
            If _observerList.Contains(observer) Then _observerList.Remove(observer)
        End Sub

        ''' <summary>
        ''' 清空站位修改观察者
        ''' </summary>
        Public Sub ClearStatisticsObserver()
            _observerList.Clear()
        End Sub

        ''' <summary>
        ''' 初始化完成
        ''' </summary>
        ''' <returns></returns>
        Public Property IsInitialized As Boolean

        ''' <summary>
        ''' 用户账号信息
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property Account As UserInfo
            Get
                Return _userInfo
            End Get
        End Property


        ''' <summary>
        ''' 服务索引
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ServiceIndex As Integer
            Get
                Return _serviceIndex
            End Get
        End Property

        ''' <summary>
        ''' 服务角色,0客户端，1服务器
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ServiceRoles As Integer
            Get
                Return _serviceRoles
            End Get
        End Property

        ''' <summary>
        ''' 服务别名
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ServiceAlias As String
            Get
                Return _serviceAlias
            End Get
        End Property

        ''' <summary>
        ''' 服务所属分组
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ServiceGroup As String
            Get
                Return _serviceGroup
            End Get
        End Property


        ''' <summary>
        ''' 鉴权文件信息
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property License As License.License
            Get
                Return _license
            End Get
        End Property


        ''' <summary>
        ''' 工厂产线信息
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ProductionLines() As ProductionLinesManager
            Get
                Return ProductionLinesManager.CreateManager()
            End Get
        End Property


        ''' <summary>
        ''' 测试站信息
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property TestResult() As TestResult
            Get
                Return _testResult
            End Get
        End Property


        ''' <summary>
        ''' 测试站信息
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ProcessStation() As ProcessStation
            Get
                Return _processStation
            End Get
        End Property


        ''' <summary>
        ''' APP注册机
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property Register() As AppRegister
            Get
                Return _register
            End Get
        End Property

        ''' <summary>
        ''' 测试记录表名
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property TestLogTableName() As String
            Get
                Return _testLogTableName
            End Get
        End Property

        ''' <summary>
        ''' 未查询到数据库订单号时是否显示提示
        ''' </summary>
        ''' <returns></returns>
        Public Property ShowUnSearchOrderIDTip() As Boolean

        ''' <summary>
        ''' 允许保存未查询到订单号的记录入库,显示提示时,此字段不生效。
        ''' </summary>
        ''' <returns></returns>
        Public Property SaveUnSearchOrderIDLog() As Boolean

        Private _testChangedTime As DateTime

        ''' <summary>
        ''' 初始化信息,唯一初始化
        ''' </summary>
        ''' <param name="sType">软件选择站位时，可以选择的站位类型,默认显示测试站位</param>
        Public Sub Initialize(Optional sType As ProcessStation.StationTypeEnum = ProcessStation.StationTypeEnum.Test)
            If IsInitialized = True Then Return
            IsInitialized = True

            '建立Tcp与服务通讯的套接字
            ConnectDataService()

            '显示登录窗体
            ShowLoginForm()

            '注册软件
            RegisterApp()

            '给测试记录附上初始值
            InitializeTestResult()

            '记录站位类型提供过滤筛选
            _stationType = sType

            '记录测试变化信息
            _testChangedTime = Now
            AddHandler TestStatusMonitor.TestStatusChanged, AddressOf TestStatusChanged
        End Sub

        ''' <summary>
        ''' 测试状态改变处理事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub TestStatusChanged(sender As Object, e As TestStatusChangedEventArgs)
            '记录上一次变化的时间
            _testChangedTime = Now
        End Sub


#Region "服务通讯模块"
        ''' <summary>
        ''' 连接数据服务,异步执行
        ''' </summary>
        Public Sub ConnectDataService()
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf KeepTcpClientAlive))
        End Sub

        ''' <summary>
        ''' 保持与数据服务的Tcp连接存活
        ''' </summary>
        ''' <param name="state"></param>
        Private Sub KeepTcpClientAlive(state As Object)
            Static remoteIp As String = "127.0.0.1"

            While True
                Try
                    If _tcpClient Is Nothing OrElse _tcpClient.Client Is Nothing Then
                        _tcpClient = New TcpClient(remoteIp, CInt(UtsRegistry.DataServicePort))

                        '开启监听
                        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ClientReceive), _tcpClient)

                        '通知服务软件启动
                        SendAppMsg(_tcpClient, TaskJsonParam.AppMsgTypes.AppStart)

                        '开启与服务通知心跳包
                        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SendAppAlive), _tcpClient)
                    End If
                Catch ex As Exception
                    Console.WriteLine($"InitTcpClient Error:{ex.Message}!")
                End Try

                Thread.Sleep(1000 * 10)
            End While
        End Sub

        ''' <summary>
        ''' 定期发送App心跳包
        ''' </summary>
        ''' <param name="state"></param>
        Private Sub SendAppAlive(state As Object)
            Dim client As TcpClient = CType(state, TcpClient)
            While True
                If client Is Nothing OrElse client.Client Is Nothing Then Return

                Thread.Sleep(1000)

                SendAppMsg(client, TaskJsonParam.AppMsgTypes.AppAlive)

            End While
        End Sub

        ''' <summary>
        ''' 主动向服务发送变化数据
        ''' </summary>
        ''' <param name="type">变化类型</param>
        ''' <param name="fileds">字段内容</param>
        Public Sub SendAppMsg(type As TaskJsonParam.AppMsgTypes, fileds As Dictionary(Of String, String))
            If _tcpClient Is Nothing OrElse _tcpClient.Client Is Nothing Then Return

            Dim param As New TaskJsonParam
            param.CmdName = TaskJsonParam.CmdNamesEnum.AppMsg
            param.AppName = Application.ProductName

            If _userInfo Is Nothing Then
                param.User = "Admin"
            Else
                param.User = _userInfo.UserName
            End If

            param.AppInfo.Add("AppStatus", type.ToString)
            For Each filed As KeyValuePair(Of String, String) In fileds
                param.AppInfo.Add(filed.Key, filed.Value)
            Next

            SendJsonString(_tcpClient, TaskJsonParam.SerializeToJson(param) & vbCrLf)
        End Sub


        ''' <summary>
        ''' 发送App上报信息
        ''' </summary>
        ''' <param name="client"></param>
        ''' <param name="type"></param>
        Private Sub SendAppMsg(client As TcpClient, type As TaskJsonParam.AppMsgTypes)
            If client Is Nothing OrElse client.Client Is Nothing Then Return

            Dim param As New TaskJsonParam
            param.CmdName = TaskJsonParam.CmdNamesEnum.AppMsg
            param.AppName = Application.ProductName

            If _userInfo Is Nothing Then
                param.User = "Admin"
            Else
                param.User = _userInfo.UserName
            End If

            Select Case type
                Case TaskJsonParam.AppMsgTypes.AppStart
                    param.AppInfo.Add("AppStatus", TaskJsonParam.AppMsgTypes.AppStart.ToString)
                    param.AppInfo.Add("Version", Application.ProductVersion)
                    param.AppInfo.Add("AppPath", Application.StartupPath)
                Case TaskJsonParam.AppMsgTypes.AppClose
                    param.AppInfo.Add("AppStatus", TaskJsonParam.AppMsgTypes.AppClose.ToString)
                Case TaskJsonParam.AppMsgTypes.AppAlive
                    param.AppInfo.Add("AppStatus", TaskJsonParam.AppMsgTypes.AppAlive.ToString)
                    param.AppInfo.Add("Version", Application.ProductVersion)

                    If _processStation Is Nothing Then
                        param.AppInfo.Add("Project", "")
                        param.AppInfo.Add("Station", "")
                        param.AppInfo.Add("TestPlan", "")
                    Else
                        param.AppInfo.Add("Project", _processStation.ParentProject.Name)
                        param.AppInfo.Add("Station", _processStation.Name)
                        param.AppInfo.Add("TestPlan", _processStation.Packet.FileName)
                    End If

                    param.AppInfo.Add("UtsStatus", StatusMonitor.ComportStatusMonitor.ComportStatus.ToString)
                    param.AppInfo.Add("TestStatus", StatusMonitor.TestStatusMonitor.TestStatus.ToString)
                Case TaskJsonParam.AppMsgTypes.StationChanged
                    param.AppInfo.Add("AppStatus", TaskJsonParam.AppMsgTypes.StationChanged.ToString)
                    param.AppInfo.Add("Project", _processStation.ParentProject.Name)
                    param.AppInfo.Add("Station", _processStation.Name)
                    param.AppInfo.Add("TestPlan", _processStation.Packet.FileName)
            End Select

            SendJsonString(client, TaskJsonParam.SerializeToJson(param) & vbCrLf)
        End Sub


        ''' <summary>
        ''' 发送数据
        ''' </summary>
        ''' <param name="tcpClient"></param>
        ''' <param name="jsonString"></param>
        Private Sub SendJsonString(tcpClient As TcpClient, jsonString As String)
            Static SendLock As New Object
            Static FailCount As Integer = 0

            If tcpClient Is Nothing OrElse tcpClient.Client Is Nothing Then Return

            SyncLock SendLock
                Try
                    Dim buf() As Byte = Encoding.UTF8.GetBytes(jsonString)
                    tcpClient.GetStream().Write(buf, 0, buf.Length)
                    FailCount = 0
                Catch ex As Exception
                    FailCount += 1
                    If FailCount > 3 Then
                        FailCount = 0
                        tcpClient.Close()
                    End If
                    Console.WriteLine($"TcpClient Send Data Error!{ex.Message}")
                End Try
            End SyncLock
        End Sub

        ''' <summary>
        ''' APP接收服务器数据
        ''' </summary>
        ''' <param name="state"></param>
        Public Sub ClientReceive(state As Object)
            Dim client As TcpClient = CType(state, TcpClient)
            Dim len As Integer
            Dim buf(4096) As Byte

            While True
                Try
                    len = client.Client.Receive(buf)
                Catch ex As Exception
                    Console.WriteLine($"TcpServer  Receive Error:{ex.Message},Recycling Connection!")
                    Exit While
                End Try

                If len = 0 Then
                    Console.WriteLine($"TcpServer {client.Client.RemoteEndPoint} Is Disconnect.")
                    Exit While
                End If

                Dim destBuf(len - 1) As Byte
                Array.Copy(buf, 0, destBuf, 0, destBuf.Length)
                ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf DealData), New TcpData(client, destBuf))
            End While
        End Sub

        Public Sub DealData(state As Object)
            Dim data As TcpData = CType(state, TcpData)
            Dim jsonStrings As String = Encoding.UTF8.GetString(data.Buffer)

            '校验Json字符串，必须以回车换行结尾
            If jsonStrings.EndsWith(vbCrLf) = False Then Return

            For Each jsonString As String In jsonStrings.Split(New String() {vbCrLf}, Integer.MaxValue, StringSplitOptions.RemoveEmptyEntries)
                Try
                    '反序列化
                    Dim taskParam As TaskJsonParam = TaskJsonParam.DeserializeFormJson(jsonString)

                    '反序列化失败,则处理下一包
                    If IsNothing(taskParam) Then Continue For

                    '处理数据,返回回复数据
                    Dim reply As TaskJsonParam = DealReceiveData(taskParam)

                    '无需回复,则处理下一包
                    If reply Is Nothing Then Continue For

                    '序列化回复数据
                    Dim replyString As String = TaskJsonParam.SerializeToJson(reply) & vbCrLf

                    '回复数据
                    SendJsonString(data.Client, replyString)
                Catch ex As Exception
                    Console.WriteLine($"Deal Receive Data Error!{ex.Message}")
                End Try
            Next
        End Sub



        ''' <summary>
        ''' 处理数据,并返回回复数据
        ''' </summary>
        ''' <param name="taskParam">需要处理的数据参数</param>
        ''' <returns>需要回复的数据</returns>
        Private Function DealReceiveData(taskParam As TaskJsonParam) As TaskJsonParam
            Dim replyParam As TaskJsonParam
            Select Case taskParam.CmdName
                Case TaskJsonParam.CmdNamesEnum.AppMsg
                    replyParam = Nothing '不处理

                    If taskParam.CmdStatus = "Fail" Then Exit Select

                    Dim status As TaskJsonParam.AppMsgTypes
                    Try
                        status = CType([Enum].Parse(GetType(TaskJsonParam.AppMsgTypes), taskParam.AppInfo("AppStatus")), TaskJsonParam.AppMsgTypes)

                        Select Case status
                            Case TaskJsonParam.AppMsgTypes.AppAlive
                                Static dbLastStatus As Integer = -1
                                Static ftpLastStatus As Integer = -1
                                Static cacheLastStatus As Integer = -1
                                Static syncLastStatus As String = ""
                                Static servicesLastStatus As String = ""

                                Dim dbStatus As Integer = -1
                                Dim ftpStatus As Integer = -1
                                Dim cacheCount As Integer = -1

                                Integer.TryParse(taskParam.AppInfo("DbStatus"), dbStatus)
                                If dbLastStatus <> dbStatus Then
                                    dbLastStatus = dbStatus
                                    RaiseEvent DbStatusChanged(dbLastStatus)
                                End If

                                Integer.TryParse(taskParam.AppInfo("FtpStatus"), ftpStatus)
                                If ftpLastStatus <> ftpStatus Then
                                    ftpLastStatus = ftpStatus
                                    RaiseEvent FtpStatusChanged(dbLastStatus)
                                End If

                                Dim flg As Boolean = False '是否更新同步状态文本
                                Integer.TryParse(taskParam.AppInfo("CacheCount"), cacheCount)
                                If cacheLastStatus <> cacheCount Then
                                    cacheLastStatus = cacheCount
                                    flg = True
                                End If

                                Dim syncTime As String = taskParam.AppInfo("SyncTime")
                                If syncLastStatus <> syncTime Then
                                    syncLastStatus = syncTime
                                    flg = True
                                End If

                                If flg Then
                                    RaiseEvent SyncTimeChanged($"[{cacheLastStatus}] {syncLastStatus}")
                                End If

                                Dim tmpTime As Date
                                If Date.TryParse(syncTime, tmpTime) Then
                                    If (Now - tmpTime).TotalMinutes > 6 Then
                                        DatabaseStatusMonitor.DatabaseSyncStatus = DatabaseStatusMonitor.DatabaseSyncStatusEnum.UnCompleted
                                    Else
                                        DatabaseStatusMonitor.DatabaseSyncStatus = DatabaseStatusMonitor.DatabaseSyncStatusEnum.Completed
                                    End If
                                Else
                                    DatabaseStatusMonitor.DatabaseSyncStatus = DatabaseStatusMonitor.DatabaseSyncStatusEnum.Unknown
                                End If

                                Dim services As String = taskParam.AppInfo("Services")
                                If servicesLastStatus <> services Then
                                    servicesLastStatus = services
                                    RaiseEvent ServicesChanged(servicesLastStatus)
                                End If
                            Case Else
                                Console.WriteLine($"status:{status}")
                        End Select
                    Catch ex As Exception

                    End Try

                Case TaskJsonParam.CmdNamesEnum.ServiceMsg
                    replyParam = DealServiceMsg(taskParam)
                Case Else
                    replyParam = Nothing
                    Console.WriteLine($"Invalid CmdName:{taskParam.CmdName}")
            End Select
            Return replyParam
        End Function

        Public Event DbStatusChanged(status As Integer)
        Public Event FtpStatusChanged(status As Integer)
        Public Event SyncTimeChanged(timeString As String)
        Public Event ServicesChanged(services As String)


        Private Function DealServiceMsg(taskParam As TaskJsonParam) As TaskJsonParam
            Dim replyParam As New TaskJsonParam(taskParam.CmdName, True)

            Try
                If taskParam.AppInfo Is Nothing OrElse taskParam.AppInfo.Count = 0 Then Return Nothing

                '依此判断App修改类型
                Dim status As TaskJsonParam.ServiceMsgTypes
                status = CType([Enum].Parse(GetType(TaskJsonParam.ServiceMsgTypes), taskParam.AppInfo("AppStatus")), TaskJsonParam.ServiceMsgTypes)

                Select Case status
                    Case TaskJsonParam.ServiceMsgTypes.DbHostChange
                        UtsDb.DbHostChanged(taskParam.AppInfo("DbHost"))
                    Case TaskJsonParam.ServiceMsgTypes.FtpHostChange
                        UtsFtp.CreateObject.FtpHost = taskParam.AppInfo("FtpHost")
                End Select

                replyParam.CmdStatus = TaskJsonParam.CmdStatusEnum.Pass.ToString()
            Catch ex As Exception
                replyParam.CmdStatus = TaskJsonParam.CmdStatusEnum.Fail.ToString()
                replyParam.CmdMsg = ex.Message
            End Try

            Return replyParam
        End Function

        Public Class TcpData
            Sub New(c As TcpClient, buf() As Byte)
                Client = c
                Buffer = buf
            End Sub

            Public Client As TcpClient

            Public Buffer() As Byte
        End Class
#End Region


        ''' <summary>
        ''' 显示登陆页面
        ''' </summary>
        Private Sub ShowLoginForm()
            If LoginParams.IsShowLoginForm = False Then Return
            Using frmLogin As New LoginForm
                If frmLogin.ShowDialog() = DialogResult.OK Then
                    _userInfo = frmLogin.UserLoginInfo
                    _license = frmLogin.UserLicense
                Else
                    Throw New Exception($"User Quit!")
                End If
            End Using
        End Sub


        ''' <summary>
        ''' 注册APP
        ''' </summary>
        Private Sub RegisterApp()
            _serviceIndex = CInt(UtsRegistry.DataServiceIndex)
            _serviceRoles = CInt(UtsRegistry.Roles)
            _serviceAlias = UtsRegistry.DataServiceAlias
            _serviceGroup = UtsRegistry.BarnchNet
            _appName = Application.ProductName
            _appVersion = Application.ProductVersion

            AppRegister.CreateAppListTable() '创建日志列表
            AppRegister.CreateAppLogTable() '创建日志记录表
            _register = New AppRegister(_serviceIndex, _appName, _appVersion)
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf UpdateAppAliveTime))
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SaveServiceLog))
        End Sub

        ''' <summary>
        ''' 初始化测试结果字段信息
        ''' </summary>
        Private Sub InitializeTestResult()
            _testResult.UserID = Account.UserId
            _testResult.ServiceID = _serviceIndex
            _testResult.AppName = _appName & _appVersion
        End Sub

        ''' <summary>
        ''' 填充测试结果订单信息字段
        ''' </summary>
        Private Sub FillTestResultOrderID()
            _testResult.OrderID = DbConnector.SearchOrderID(_processStation.ParentProject.Index, _testResult.DUT_SN)

            If _testResult.OrderID = -1 Then
                '仅自动生成条码模式下保证有订单号,其余模式条码不检测
                If _processStation.SnType <> ProcessStation.SnTypeEnum.Auto Then Return
                If ShowUnSearchOrderIDTip Then
                    If MsgBox($"未查询到条码[{_testResult.DUT_SN}]对应的订单号,是否继续录入？", MsgBoxStyle.OkCancel, "Tip") <> MsgBoxResult.Ok Then
                        Throw New Exception($"未查询条码[{_testResult.DUT_SN}]到指定订单号")
                    End If
                Else
                    If SaveUnSearchOrderIDLog = False Then
                        Throw New Exception($"未查询条码[{_testResult.DUT_SN}]到指定订单号")
                    End If
                End If
            End If
        End Sub

        ''' <summary>
        ''' 根据序号分配给测试记录的订单号，并将测试记录写入到数据库中，提交成功后会重置测试记录。
        ''' </summary>
        Public Sub CommitTestResult(Optional uniqueRecord As Boolean = False)
            '填充订单号
            FillTestResultOrderID()

            '提交测试记录
            If uniqueRecord Then
                DbConnector.SaveUniqueTestLog(_testLogTableName, _processStation, _testResult)
            Else
                DbConnector.SaveTestLog(_testLogTableName, _processStation, _testResult)
            End If

        End Sub


        ''' <summary>
        ''' 根据项目名与站位名称，加载项目站信息
        ''' </summary>
        ''' <param name="projectName"></param>
        ''' <param name="stationName"></param>
        Public Sub LoadStation(projectName As String, stationName As String, Optional filed As Dictionary(Of String, String) = Nothing)
            If String.IsNullOrWhiteSpace(projectName) Or String.IsNullOrWhiteSpace(stationName) Then
                Return
            End If

            Using dlg As New DlgLoadStation
                dlg.UserInfo = Account '用与初始化项目信息时,更新操作者，同时可用与根据用户权限筛选项目
                If dlg.InitProjectStationWithoutShow(projectName, stationName) Then
                    _processStation = dlg.ProcessStation
                    projectInfo = dlg._projectInfo
                    If String.IsNullOrEmpty(ProcessStation.Packet.FileName) Then
                        ProcessStation.Packet.CreatePacket() '新建测试站包
                    Else
                        ProcessStation.Packet.LoadPacket() '读取测试站包
                    End If

                    StationChanged(ProcessStation, filed) '测试站修改
                End If
            End Using
        End Sub

        ''' <summary>
        ''' 显示切换项目站信息页面，供用户修改测试站
        ''' </summary>
        Public Sub ChangeStation(Optional filed As Dictionary(Of String, String) = Nothing)
            Using dlg As New DlgLoadStation
                dlg.UserInfo = Account '用与初始化项目信息时,更新操作者，同时可用与根据用户权限筛选项目

                If _processStation Is Nothing Then
                    If dlg.ShowDialog("", "", _stationType) <> DialogResult.OK Then Return
                Else
                    If dlg.ShowDialog(_processStation.ParentProject.Name, _processStation.Name, _stationType) <> DialogResult.OK Then Return
                End If

                If dlg.ProcessStation Is Nothing Then Return
                _processStation = dlg.ProcessStation
                projectInfo = dlg._projectInfo
                If String.IsNullOrEmpty(ProcessStation.Packet.FileName) Then
                    ProcessStation.Packet.CreatePacket() '新建测试站包
                Else
                    ProcessStation.Packet.LoadPacket() '读取测试站包
                End If
                StationChanged(ProcessStation, filed)

            End Using
        End Sub

        '2022-10-19 CZH 该改动针对已固定某一站的 资源包刷新
        Public Sub ChangeStation(processStation As ProcessStation， Optional filed As Dictionary(Of String, String) = Nothing)
            'Using dlg As New DlgLoadStation
            '    dlg.UserInfo = Account '用与初始化项目信息时,更新操作者，同时可用与根据用户权限筛选项目

            '    If _processStation Is Nothing Then
            '        If dlg.ShowDialog("", "", _stationType) <> DialogResult.OK Then Return
            '    Else
            '        If dlg.ShowDialog(_processStation.ParentProject.Name, _processStation.Name, _stationType) <> DialogResult.OK Then Return
            '    End If

            If processStation Is Nothing Then Return
            _processStation = processStation

            If String.IsNullOrEmpty(processStation.Packet.FileName) Then
                processStation.Packet.CreatePacket() '新建测试站包
            Else
                processStation.Packet.LoadPacket() '读取测试站包
            End If
            StationChanged(processStation, filed)

            'End Using
        End Sub


        ''' <summary>
        ''' 用户选择测试站后回调函数
        ''' </summary>
        ''' <param name="station"></param>
        ''' <param name="filed"></param>
        Private Sub StationChanged(station As ProcessStation, Optional filed As Dictionary(Of String, String) = Nothing)
            _testLogTableName = TestLogTable.TableName(station.ParentProject.Index, ProcessStation.StationID)

            '本地新建测试记录表
            DbConnector.UtsCreateTestLogTableToLocal(_testLogTableName)

            '添加预添加列
            If filed IsNot Nothing AndAlso filed.Count > 0 Then
                DbConnector.AddTestLogCols(_testLogTableName, filed)
            End If

            '修改测试记录中测试流程
            _testResult.TestPlan = _processStation.Packet.FileName

            'App日志
            _register.ProjectName = _processStation.ParentProject.Name
            _register.StationName = _processStation.Name
            _register.TestPlan = _processStation.Packet.FileName
            _register.AppendTraceLog($"Station Changed,PN:{station.ParentProject.Name},SN:{station.Name}.")
            _register.AppMsg = $"PN:{_processStation.ParentProject.Name},SN:{_processStation.Name},TP:{_register.TestPlan}"

            '触发其他页面的站位修改事件
            For Each observer As IProcessStation In _observerList
                observer.StationChanged()
            Next
        End Sub

        ''' <summary>
        ''' 定期更新APP存活时间
        ''' </summary>
        ''' <param name="state"></param>
        Private Sub UpdateAppAliveTime(state As Object)
            Dim Interval As Integer = 1000 * 60 * 1 '单位ms

            While _disposedValue = False

                If (Now - _testChangedTime).TotalMinutes >= 1 AndAlso TestStatusMonitor.TestStatus <> TestStatusMonitor.TestStatusEnum.Testing Then
                    _register.AppStatus = 0
                Else
                    _register.AppStatus = 1
                End If

                Try
                    _register.UpdateAliveTime()
                Catch ex As Exception
                    Console.WriteLine($"UpdateAppAliveTime Error:{ex.Message}")
                End Try

                Thread.Sleep(Interval)
            End While
        End Sub

        ''' <summary>
        ''' 保存软件运行日志至数据库
        ''' </summary>
        ''' <param name="state"></param>
        Private Sub SaveServiceLog(state As Object)
            Dim Interval As Integer = 1000 * 60 * 1 '单位ms

            While _disposedValue = False
                SaveServiceLogQueueToDb()

                Thread.Sleep(Interval)
            End While
        End Sub

        ''' <summary>
        ''' 保存软件运行日志至数据库
        ''' </summary>
        Private Sub SaveServiceLogQueueToDb()
            Try
                If _register IsNot Nothing Then
                    _register.SaveLogQueueToDb()
                End If
            Catch ex As Exception
                Console.WriteLine($"SaveServiceLog Error:{ex.Message}")
            End Try
        End Sub


        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not _disposedValue Then
                If disposing Then
                    '释放托管状态(托管对象)
                End If

                '释放未托管的资源(未托管的对象)并替代终结器
                '将大型字段设置为 null

                _disposedValue = True

                SaveServiceLogQueueToDb()
            End If
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            ' 不要更改此代码。请将清理代码放入“Dispose(disposing As Boolean)”方法中
            Dispose(disposing:=True)
            GC.SuppressFinalize(Me)
        End Sub

    End Class
End Namespace