Imports System.IO.Ports
Imports System.Windows.Forms

Public Class weightForm
    Private weightSum As Integer
    Private switchMotion As Boolean = False

    Private weightErrorPlus As Integer
    Private weightErrorMinus As Integer


    Private weightMode As Boolean
    Private weightStart As Boolean

    Private Delegate Sub serialDelegate()
    Private updateDelegate As serialDelegate
    Private weightResult As Integer
    Private weightResult2 As Double = 0
    Private zeroSet As Boolean = True

    Private weightBuffer As New List(Of Double) ' 무게 버퍼
    Private Const BUFFER_SIZE As Integer = 3 ' 버퍼 크기 (3개로 축소)
    Private Const STABILITY_THRESHOLD As Double = 5.0 ' 안정성 임계값 (5g로 완화)


    Private weight(2)
    Private weight2(1) As String
    Private Sub weightForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ZeroTimer.Enabled = True
        lbNowWeight.Text = Nothing
        lbWeightEX.Text = Nothing
        weightSum = mainForm.weightSum
        lbNowWeight.Refresh()
        lbWeightEX.Refresh()

        weightErrorPlus = Val(mainForm.txbWeightPlus.Text)
        weightErrorMinus = Val(mainForm.txbWeightMinus.Text)

        lbError.Text = "(오차: +" & weightErrorPlus & ", -" & weightErrorMinus & ")"


        weightResult = 0
        zeroSet = True
        weightMode = mainForm.rdbWeightAuto.Checked
        weightStart = mainForm.weightStart
    End Sub

    Private Sub playTimer_Tick(sender As Object, e As EventArgs) Handles playTimer.Tick
        Dim scaleData As String

        If mainForm.rdbWeightAuto.Checked = True Then
            If weightResult > 0 Then
                statusTimer.Enabled = False
                playTimer.Enabled = False

                lbNowWeight.Text = weightResult

                If weight_compare() Then
                    lbWeight.BackColor = Color.Green
                    lbWeight.Text = "무게 일치"
                    delay(2000)
                    mainForm.weightResult = lbNowWeight.Text
                    mainForm.weightOkNg = True
                    Me.DialogResult = DialogResult.OK

                Else
                    lbWeight.BackColor = Color.Red
                    lbWeight.Text = "무게 불일치"
                    delay(2000)
                    mainForm.weightOkNg = False

                    Me.DialogResult = DialogResult.No
                End If

            End If
        ElseIf mainForm.rdbWeightQW.Checked = True Then

            If weightResult2 > 5 Then ' 5g 이상이면 측정 시작
                ' 실시간 무게 표시
                lbNowWeight.Text = Math.Round(weightResult2, 0).ToString()
                lbWeight.BackColor = Color.Yellow
                lbWeight.Text = "측정중 (" & Math.Round(weightResult2, 0).ToString() & "g)"

                ' 무게 버퍼에 추가 (안정성 확인용)
                AddToWeightBuffer(weightResult2)

                ' 버퍼가 충분히 쌓이면 안정성 검사
                If weightBuffer.Count >= 3 AndAlso IsWeightStable() Then
                    statusTimer.Enabled = False
                    playTimer.Enabled = False

                    Dim stableWeight As Double = GetStableWeight()
                    lbNowWeight.Text = Math.Round(stableWeight, 0).ToString()

                    If weight_compare_improved(stableWeight) Then
                        lbWeight.BackColor = Color.Green
                        lbWeight.Text = "무게 일치"
                        delay(2000)
                        mainForm.weightResult = lbNowWeight.Text
                        mainForm.txbCheckWeight.Text = lbNowWeight.Text
                        mainForm.weightOkNg = True
                        Me.DialogResult = DialogResult.OK
                    Else
                        zeroSet = False
                        lbWeight.BackColor = Color.Red
                        lbWeight.Text = "무게 불일치"
                        ZeroTimer.Enabled = True
                    End If
                End If
            End If
        Else
            scaleData = Mid(MeasureScale(200), 2, weight.Length)

            If scaleData > 5 Then
                statusTimer.Enabled = False
                lbWeight.BackColor = Color.Yellow
                lbWeight.Text = "측정중"
                playTimer.Enabled = False
                If AutoMeasureScale() Then

                    lbNowWeight.Text = Val(weight(1))

                    If weight_compare() Then
                        lbWeight.BackColor = Color.Green
                        lbWeight.Text = "무게 일치"
                        delay(2000)
                        mainForm.weightResult = lbNowWeight.Text
                        mainForm.txbCheckWeight.Text = lbNowWeight.Text
                        mainForm.weightOkNg = True
                        Me.DialogResult = DialogResult.OK
                    Else
                        zeroSet = False
                        lbWeight.BackColor = Color.Red
                        lbWeight.Text = "무게 불일치"
                        ZeroTimer.Enabled = True
                    End If
                Else
                    lbWeight.Text = "무게 측정 불안정"
                    lbWeight.BackColor = Color.Red
                End If
            End If
        End If

    End Sub

    ' 무게 버퍼에 추가하는 함수
    Private Sub AddToWeightBuffer(weight As Double)
        weightBuffer.Add(weight)

        ' 버퍼 크기 초과 시 가장 오래된 값 제거
        If weightBuffer.Count > BUFFER_SIZE Then
            weightBuffer.RemoveAt(0)
        End If
    End Sub

    ' 무게가 안정한지 확인하는 함수
    Private Function IsWeightStable() As Boolean
        If weightBuffer.Count < BUFFER_SIZE Then
            Return False
        End If

        Dim maxWeight As Double = weightBuffer.Max()
        Dim minWeight As Double = weightBuffer.Min()

        ' 최대값과 최소값의 차이가 임계값보다 작으면 안정
        Return (maxWeight - minWeight) <= STABILITY_THRESHOLD
    End Function

    ' 안정된 무게값을 얻는 함수 (평균값 사용)
    Private Function GetStableWeight() As Double
        If weightBuffer.Count = 0 Then
            Return 0
        End If

        Return weightBuffer.Average()
    End Function

    ' 개선된 무게 비교 함수
    Private Function weight_compare_improved(currentWeight As Double) As Boolean
        Dim targetWeight As Double = weightSum
        Dim upperLimit As Double = targetWeight + weightErrorPlus
        Dim lowerLimit As Double = targetWeight - weightErrorMinus

        Return currentWeight >= lowerLimit And currentWeight <= upperLimit
    End Function

    Private Sub Status_timer_Tick(sender As Object, e As EventArgs) Handles statusTimer.Tick
        If switchMotion = True Then
            lbWeight.BackColor = Color.MediumSlateBlue
            switchMotion = False
        Else
            lbWeight.BackColor = Color.Gold
            switchMotion = True
        End If
    End Sub

    Private Sub Zero_Timer_Tick(sender As Object, e As EventArgs) Handles ZeroTimer.Tick
        Dim scaledata As String

        Try

            If mainForm.rdbWeightAuto.Checked = True Then
                If zeroSet = True Then
                    statusTimer.Enabled = True
                    playTimer.Enabled = True
                    ZeroTimer.Enabled = False
                    lbWeightEX.Text = weightSum
                    lbWeight.Text = "저울에 올려주세요"
                End If

            ElseIf mainForm.rdbWeightQW.Checked = True Then

                lbNowWeight.Text = Math.Round(weightResult2, 0).ToString()
                ' 무게 불일치 후 재측정 모드를 먼저 체크
                If zeroSet = False Then
                    ' 무게가 변경되었는지 확인 (이전 측정값과 5g 이상 차이나면 재측정 시작)
                    Static previousWeight As Double = 0

                    If Math.Abs(weightResult2 - previousWeight) >= 5 Then
                        ' 무게 변화 감지 - 재측정 시작
                        statusTimer.Enabled = True
                        playTimer.Enabled = True
                        ZeroTimer.Enabled = False
                        lbWeightEX.Text = weightSum
                        lbWeight.Text = "재측정 중..."
                        lbWeight.BackColor = Color.Yellow

                        ' 버퍼 초기화
                        weightBuffer.Clear()
                        previousWeight = weightResult2
                    Else
                        ' 무게 변화 없음 - 계속 대기
                        lbWeight.Text = "무게를 조정해주세요"
                        lbWeight.BackColor = Color.Orange
                        ZeroTimer.Enabled = True
                        previousWeight = weightResult2
                    End If

                ElseIf weightResult2 <= 0 Then
                    statusTimer.Enabled = True
                    playTimer.Enabled = True
                    ZeroTimer.Enabled = False
                    lbWeightEX.Text = weightSum
                    lbWeight.Text = "저울에 올려주세요"
                    lbWeight.BackColor = Color.White
                Else
                    ZeroTimer.Enabled = False
                    lbWeight.Text = "저울을 비워주세요."
                    lbWeight.BackColor = Color.Red
                    ZeroTimer.Enabled = True
                End If
            Else
                scaledata = Mid(MeasureScale(200), 2, weight.Length)

                If scaledata = 0 Then
                    statusTimer.Enabled = True
                    playTimer.Enabled = True
                    ZeroTimer.Enabled = False
                    lbWeightEX.Text = weightSum
                    lbWeight.Text = "저울에 올려주세요"

                Else
                    ZeroTimer.Enabled = False
                    lbWeight.Text = " 저울을 비워주세요"
                    lbWeight.BackColor = Color.Red
                    ZeroTimer.Enabled = True
                End If
            End If

        Catch ex As Exception
            ZeroTimer.Enabled = False
            mainForm.errorGen(Err.Description & "Zero_Timer_Tick_Scale_Error")
        End Try
    End Sub

    Private Function weight_compare() As Boolean
        If lbNowWeight.Text >= weightSum - weightErrorMinus And lbNowWeight.Text <= weightSum + weightErrorPlus Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Sub delay(ByVal milliSecond As Double)
        Dim delayTime As Date = Now.AddSeconds(milliSecond / 1000)
        Do Until Now > delayTime
            Application.DoEvents()
        Loop
    End Sub

    Private Function MeasureScale2(timeout As Integer) As String
        'Return "US,GS,   " & weightResult2.ToString("F3") & " kg"
        Return "US,GS,   " & (weightResult2 * 1000).ToString("F0") & " g"
    End Function

    Private Function AutoMeasureScale() As Boolean
        Try
            If mainForm.rdbWeightQW.Checked = True Then
                ' 2번 측정해서 무게가 거의 같으면 OK
                For i = 0 To 1
                    weight2(i) = MeasureScale2(200) ' 예: "US,GS,   0.901 kg"
                Next

                Dim w0 As Double = ParseWeightData(weight2(0))
                Dim w1 As Double = ParseWeightData(weight2(1))

                If Math.Abs(w0 - w1) < 10 Then ' 10g 이내 차이 (kg 단위면 0.01)
                    Return True
                Else
                    Return False
                End If
            End If
            Do
                For i = 0 To 1
                    weight(i) = MeasureScale(200)
                    If Mid(weight(i), 1, 1) = "U" Then
                        Exit For
                    ElseIf Mid(weight(i), 1, 1) = "S" Then
                        weight(i) = Mid(weight(i), InStr(1, weight(i), "S") + 1, weight(i).Length)
                        If weight(i) = weight(1) Then
                            Exit Do
                        End If
                    End If
                Next
            Loop

            If weight(0) - weight(1) < 10 And weight(0) - weight(1) > -10 Then
                Return True
            Else
                Return False
            End If

        Catch ex As Exception
            MsgBox("자동 무게 측정 에러 : " & Err.Description)
            Return False
        End Try
    End Function

    Private Sub Weight_Count_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
        ZeroTimer.Enabled = False
        statusTimer.Enabled = False
        playTimer.Enabled = False
    End Sub
    Private Function ParseWeightData(data As String) As Double
        Try
            Dim m = System.Text.RegularExpressions.Regex.Match(data, "([-+]?\d+\.\d+|\d+)\s*(kg|g)")
            If m.Success Then
                Dim value As Double = Convert.ToDouble(m.Groups(1).Value)
                Dim unit As String = m.Groups(2).Value.ToLower()
                If unit = "kg" Then
                    value = value * 1000 ' kg → g 변환
                End If
                Return value ' g 단위로 반환
            End If
        Catch ex As Exception
            Debug.Print("파싱 오류: " & ex.Message)
        End Try
        Return 0
    End Function

    Private Sub QWSerialPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles QWSerialPort.DataReceived
        Try
            System.Threading.Thread.Sleep(300) '딜레이

            Dim incoming As String = QWSerialPort.ReadExisting()
            'Debug.Print("수신 데이터: " & incoming)

            ' 여러 줄이 들어올 수 있으니, 줄 단위로 분리
            Dim lines() As String = incoming.Split({vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries)
            Dim maxWeight As Double = 0

            For Each line As String In lines
                Dim w As Double = ParseWeightData(line)
                If w > maxWeight Then maxWeight = w
            Next

            weightResult2 = maxWeight
            'Debug.Print(maxWeight)
            'Debug.Print(weightResult2)

            If weightResult2 = 0 Then
                zeroSet = True
            Else
                zeroSet = False
            End If

        Catch ex As Exception
            Debug.Print("수신 오류: " & ex.Message)
        End Try
    End Sub

    Private Sub cmdSerialPort_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles cmdSerialPort.DataReceived
        Try

            If weightMode = True Then
                If weightStart = True Then
                    Dim RecBuffer() As Byte
                    Dim weightUse As Single = 0
                    Dim dataSet As String = ""
                    Dim n As Integer = cmdSerialPort.BytesToRead
                    RecBuffer = New Byte(n - 1) {}
                    cmdSerialPort.Read(RecBuffer, 0, n)

                    For cnt = 0 To RecBuffer.Length - 1
                        dataSet = dataSet & Chr(RecBuffer(cnt))
                    Next

                    Dim dataCount As Int32 = UBound(Split(dataSet, vbCr)) - 1

                    For i = 0 To dataCount
                        Dim weightData As Single = Mid(dataSet, 1, InStr(dataSet, vbCr) - 1)

                        If weightData > weightUse Then
                            weightUse = weightData
                        End If

                        If i <> dataCount Then
                            dataSet = Mid(dataSet, InStr(dataSet, vbCr) + 1, dataSet.Length)
                        End If
                    Next

                    weightResult = weightUse * 1000

                    If weightResult = 0 Then
                        zeroSet = True
                    Else
                        zeroSet = False
                    End If

                    cmdSerialPort.DiscardInBuffer()
                    cmdSerialPort.DiscardOutBuffer()

                Else
                    cmdSerialPort.DiscardInBuffer()
                    cmdSerialPort.DiscardOutBuffer()
                End If
            End If

        Catch ex As Exception
            MsgBox("데이터를 읽어올 수 없습니다. 통신을 확인하여 주십시오.", vbExclamation)
        End Try
    End Sub

End Class
