Imports System.Management
Imports System.Threading
Imports UTS_Core.Database
Imports UTS_Core.UTSModule
Imports UTS_Core.UTSModule.DbConnect
Imports UTS_Core.UTSModule.DbTableModel.Manage


Public Class ApplicationLog


    Private Shared _serviceRunning As Boolean

    Private Shared _startThread As Thread

    Private Shared ReadOnly LogLock As Object = New Object()

    Private Shared ReadOnly LogQueue As New Queue(Of Dictionary(Of String, String))

    ''' <summary>
    ''' 厂商名
    ''' </summary>
    Public Shared VendorName As String

    Public Shared Sub WriteErrorLog(msg As String)
        UTS_Core.DebugLog.ApplicationLog.WriteErrorLog(msg)

        WriteLogToLogQueue($"{UTS_Core.DebugLog.ApplicationLog.LogTypes.Error}", msg)
    End Sub

    Public Shared Sub WriteWarningLog(msg As String)
        UTS_Core.DebugLog.ApplicationLog.WriteWarningLog(msg)

        WriteLogToLogQueue($"{UTS_Core.DebugLog.ApplicationLog.LogTypes.Warn}", msg)
    End Sub

    Public Shared Sub WriteTraceLog(msg As String)
        UTS_Core.DebugLog.ApplicationLog.WriteInfoLog(msg)

        WriteLogToLogQueue($"{UTS_Core.DebugLog.ApplicationLog.LogTypes.Info}", msg)
    End Sub

    Private Shared Sub WriteLogToLogQueue(logType As String, msg As String)
        Try
            Static mac As String = ""
            Static ip As String = ""

            If String.IsNullOrEmpty(mac) OrElse String.IsNullOrEmpty(ip) Then
                Dim searcher As New ManagementObjectSearcher("select * from win32_NetworkAdapterConfiguration")
                Dim moc2 As ManagementObjectCollection = searcher.Get()
                For Each mo As ManagementObject In moc2
                    If CBool(mo("IPEnabled")) Then
                        mac = mo("MACAddress").ToString()

                        Dim a() As String = CType(mo("IpAddress"), String())
                        ip = a(0)

                        Exit For
                    End If
                Next
            End If

            Static userName As String = Environment.UserName '获取用户名 eg:Admin
            Static machineName As String = Environment.MachineName '获取电脑名称 PC
            Static osVersion As String = Environment.OSVersion.VersionString 'os 版本
            Static appName As String = $"{My.Application.Info.ProductName}" 'os 版本
            Static appVersion As String = $"{My.Application.Info.Version}" 'os 版本

            Dim dicFiled As New Dictionary(Of String, String)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DateTime}", Date.Now.ToString("yyyy-MM-dd HH:mm:ss"))
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DevPrivateIP}", ip)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DevMac}", mac)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DevOS}", osVersion)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DevName}", machineName)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.DevUserName}", userName)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.LogType}", logType)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.LogText}", msg.Replace("'", "_"))
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.CompanyName}", VendorName)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.AppName}", appName)
            dicFiled.Add($"{ServiceLogTable.ColNamesEnum.AppVersion}", appVersion)

            SyncLock LogLock
                LogQueue.Enqueue(dicFiled) '将日志信息放入缓冲队列
            End SyncLock

        Catch ex As Exception
            UTS_Core.DebugLog.ApplicationLog.WriteErrorLog($"Write ApplicationLog To LogQueue Error:{ex.Message}")
        End Try
    End Sub

    Private Shared Sub WriteLogT()

    End Sub


    Private Shared Sub WriteLogToDatabase()
        Static firstJoin As Boolean = True

        If String.IsNullOrWhiteSpace(UtsDb.LocalConnString) Then
            UTS_Core.DebugLog.ApplicationLog.WriteErrorLog($"Invalid LocalConnString!")
            Return
        End If

        Try
            Using db As New DbExecutor(UtsDb.LocalDbType, UtsDb.LocalConnString)
                db.Open()

                If firstJoin Then
                    db.ExecuteNonQuery(ServiceLogTable.CreateTableString(DbExecutor.DbTypeEnum.Sqlite))
                    firstJoin = False
                End If

                db.BeginTransaction()

                Dim dicFiled As Dictionary(Of String, String)
                Dim cmdText As String
                Dim cmdHelper As DbCmdHelper = DbCmdHelper.CreateCmdHelper(UtsDb.RemoteDbType)
                For i As Integer = 0 To LogQueue.Count - 1
                    dicFiled = LogQueue.Dequeue()

                    cmdText = db.CmdHelper.Insert(ServiceLogTable.TableName, dicFiled)
                    db.ExecuteNonQuery(cmdText) '执行语句

                    cmdText = cmdHelper.DbInsert(UtsDb.RemotePublicDb, ServiceLogTable.TableName, dicFiled)
                    DbConnector.SaveCmdStringToCacheTable(db, cmdText) '执行命令入缓存库
                Next

                db.CommitTransaction()
                db.Close()
            End Using

        Catch ex As Exception
            UTS_Core.DebugLog.ApplicationLog.WriteErrorLog($"Write ApplicationLog To LocalDB Error:{ex.Message}")
        End Try
    End Sub


    Private Shared Sub LogQueueMonitor()
        Static writeInterval As Integer = 16 '写入间隔，单位S
        Static writeMinValue As Integer = 64 '写入数据库最小值包数

        Static lastWriteTime As DateTime = Now '上一次写入间隔


        While _serviceRunning

            If (LogQueue.Count >= writeMinValue) OrElse ((Now - lastWriteTime).TotalSeconds >= writeInterval) Then

                WriteLogToDatabase()

                lastWriteTime = Now
            End If

            Thread.Sleep(100)
        End While
    End Sub

    ''' <summary>
    ''' 初始化应用日志信息
    ''' </summary>
    Public Shared Sub InitApplicationLogInfo(logDirPath As String, logFilePrefix As String)
        UTS_Core.DebugLog.ApplicationLog.LogDirPath = logDirPath
        UTS_Core.DebugLog.ApplicationLog.LogFilePrefix = logFilePrefix
    End Sub

    ''' <summary>
    ''' 开启更新服务监听
    ''' </summary>
    Public Shared Sub StartSaveLogToDatabase()
        _serviceRunning = True

        If _startThread IsNot Nothing AndAlso _startThread.IsAlive Then
            StopSaveLogToDatabase()

        End If

        _startThread = New Thread(AddressOf LogQueueMonitor)
        _startThread.Start()
    End Sub


    Public Shared Sub StopSaveLogToDatabase()
        _serviceRunning = False

        Dim lastTime As DateTime = Now
        While _startThread IsNot Nothing AndAlso _startThread.IsAlive
            If (Now - lastTime).TotalMilliseconds > 1000 Then
                _startThread.Abort()
            End If

            Thread.Sleep(10)
        End While

        If LogQueue.Count > 0 Then
            WriteLogToDatabase()
        End If
    End Sub

End Class
