Imports VB = Microsoft.VisualBasic

Public Class frmMain
    Private m_sDateFormat As String = "yyyy/MM/dd"
    Private m_bEnablePCtime As Boolean
    Private m_iTimeZoneOffset As TimeSpan = GIGATMS.TimeZoneInfo.CurrentTimeZone.StandardUtcOffset
    Private Const APP_TITLE As String = "Ethernet Reader Event Server"
    Public WithEvents m_oERReader As GIGATMS.ERReader
    Private Delegate Sub ShowMsgToTextBoxDelegate(ByVal oTextBox As TextBox, ByVal iMaxTextLength As Integer, ByVal szMessage As String)
    Private m_oShowMsgToTextBox As ShowMsgToTextBoxDelegate = Nothing
    Private m_sLogDirPath As String = "C:\MonthlyRecords\"
    Private m_sToday As String
    Private m_szEnumPortList As String

    Private Sub ShowMsgToTextBox(ByVal oTextBox As TextBox, ByVal iMaxTextLength As Integer, ByVal szMessage As String)
        Dim szData As String
        Dim l As Integer
        With oTextBox
            szData = .Text
            If .TextLength > iMaxTextLength Then
                szData = oTextBox.Text
                l = InStr(CInt(.TextLength >> 1), szData, vbCrLf)
                If l = 0 Then
                    l = Int(.TextLength >> 1)
                End If
                .Text = Mid(szData, (l + 2))
            End If
            .SelectionStart = .TextLength
            .SelectedText = System.DateTime.Now.ToString("hh:mm:ss ")
            .SelectedText = szMessage
            .SelectedText = vbCr & vbLf
        End With
    End Sub

    Private Sub ShowMsg(ByVal szMeesage As String)
        If m_oShowMsgToTextBox Is Nothing Then
            m_oShowMsgToTextBox = New ShowMsgToTextBoxDelegate(AddressOf ShowMsgToTextBox)
        End If
        Me.BeginInvoke(m_oShowMsgToTextBox, txtView, 4096, szMeesage)
    End Sub

    Private Sub MyTCPListener1_OnServerStatusChanged(ByRef sender As Object, ByVal bIsServerStarted As Boolean) Handles MyTCPListener1.OnServerStatusChanged
        If bIsServerStarted Then
            ShowMsg("Listen OK")
        Else
            ShowMsg("Close OK")
        End If
    End Sub

    Private Sub MyTCPListener1_OnMonitor(ByRef sender As Object, ByVal iMonitorDataType As GIGATMS.MyTCPClient.MonitorConstants, ByRef bytDataBuffer() As Byte) Handles MyTCPListener1.OnMonitor
        Dim szMsg As String
        Dim I As Integer
        Dim szLineHex As String
        Dim szLineASC As String
        Dim iLineLen As Integer
        Dim oTcpClient As GIGATMS.MyTCPClient = CType(sender, GIGATMS.MyTCPClient)
        Const MAX_LINE_CHARS As Integer = 16
        iLineLen = 0
        szLineHex = ""
        szLineASC = ""
        szMsg = ""
        For I = 0 To bytDataBuffer.Length - 1
            If iLineLen > 0 Then
                szLineHex += " "
            End If
            szLineHex += bytDataBuffer(I).ToString("X").PadLeft(2, "0"c)
            If bytDataBuffer(I) >= 32 AndAlso bytDataBuffer(I) <= 127 Then
                szLineASC += ChrW(bytDataBuffer(I))
            Else
                szLineASC += "."c
            End If
            iLineLen += 1
            If iLineLen >= MAX_LINE_CHARS Then
                iLineLen = 0
                szMsg += szLineHex & "   " & szLineASC
                szMsg += vbCr & vbLf
                szLineHex = ""
                szLineASC = ""
            End If
        Next
        If iLineLen > 0 Then
            For I = iLineLen To MAX_LINE_CHARS - 1
                szLineHex += "   "
                szLineASC += " "
            Next
            szMsg += szLineHex & "   " & szLineASC
            szMsg += vbCr & vbLf
            szLineHex = ""
            szLineASC = ""
        End If
        szMsg = oTcpClient.ConnectTo & ": " & iMonitorDataType.ToString() & vbCr & vbLf & szMsg
    End Sub

    Private Sub MyTCPListener1_OnConnectStatusChanged(ByRef sender As System.Object, ByVal iStatus As GIGATMS.MyTCPClient.ConnectStatusConstants, ByVal szConnectTo As System.String) Handles MyTCPListener1.OnConnectStatusChanged
        ShowMsg(iStatus.ToString() & " with " & Convert.ToString(szConnectTo))
    End Sub

    Private Delegate Sub OnDataReceiveDelegate(ByRef sender As Object, ByVal iBytesToReceive As Integer, ByRef bytDataBuffer() As Byte)
    Private m_oOnDataReceiveDelegate As New OnDataReceiveDelegate(AddressOf OnDataReceive)

    Private Sub OnDataReceive(ByRef sender As Object, ByVal iBytesToReceive As Integer, ByRef bytDataBuffer() As Byte)
        Dim oTcpClient As GIGATMS.MyTCPClient = CType(sender, GIGATMS.MyTCPClient)
        Dim oClientEventsList As List(Of GIGATMS.ClientEvents)
        Dim oItem As ListViewItem
        Dim bIsEnablePCTime As Boolean
        Dim sDeviceIP As String 'same to client IP.
        Dim sDateTime As String
        Dim sCardUID As String
        Dim sName As String
        Dim szPort As String
        Dim L As Integer
        Dim R As Integer
        Dim I As Integer

        On Error GoTo ERR_PROC
        'true:Local PC time; false:Standard UTC time
        bIsEnablePCTime = m_bEnablePCtime

        'get data here.
        oClientEventsList = GIGATMS.ClientEvents.ToClientEventsList(bIsEnablePCTime, True, bytDataBuffer, iBytesToReceive, m_iTimeZoneOffset)

        sDeviceIP = oTcpClient.ConnectTo
        L = InStr(sDeviceIP, ":")
        If L > 0 Then
            sDeviceIP = VB.Left(sDeviceIP, (L - 1))
        End If
        szPort = sDeviceIP
        szPort = "TCP" & szPort
        L = InStr(m_szEnumPortList, vbNullChar & szPort & ":")
        szPort = szPort & ":2167"
        If L > 0 Then
            L += 1
            R = InStr(L, m_szEnumPortList, vbNullChar)
            If R > L Then
                szPort = Mid(m_szEnumPortList, L, (R - L))
            End If
        End If
        L = InStr(szPort, " ")
        If L > 0 Then
            szPort = VB.Left(szPort, (L - 1))
        End If

        Dim iEventListCount As Integer = oClientEventsList.Count

        ' Remove 250 items when itemcount over 1000.
        If lvEvent.Items.Count >= 1000 Then
            Do While lvEvent.Items.Count > 750
                lvEvent.Items.RemoveAt(0)
            Loop
        End If

        For I = 0 To (iEventListCount - 1)
            sDateTime = Format(oClientEventsList(I).DateTime, m_sDateFormat & " HH:mm:ss")
            sCardUID = oClientEventsList(I).Data
            sName = oClientEventsList(I).Name
            ''Add data to listview
            oItem = lvEvent.Items.Add(sDeviceIP)
            With oItem
                .SubItems.Add(sDateTime)
                .SubItems.Add(sCardUID)
                .SubItems.Add(sName)
            End With
            oItem.Selected = True

            If (lvEvent.SelectedItems.Count > 0) Then 'When changing selection, the ListView will first deselect current row and then select new one, so we 
                lvEvent.SelectedItems.Item(0).EnsureVisible() 'scroll to the lastest one. in win10 error occur when index is not 0 here.
            End If

            Call SaveLog(oItem)
            ShowMsg("Event From: " & oTcpClient.ConnectTo & ", Time Zone: " & CStr(m_iTimeZoneOffset.ToString) & vbCrLf & oClientEventsList.Item(I).ToString() & vbCrLf)

        Next I

        '' ~~~~~>>> cancel below comment if you need to presents the led/buzzer changes when every event comes. <<<~~~~~~~~
        '' ~~~~~>>> remember to enable the RS232 command set control in the utility first. <<<~~~~~~~~
        'With m_oERReader
        '    If .PortOpen Then
        '        .PortOpen = False
        '        Call mDoEventSleep(150)
        '    End If
        '    .PortName = szPort
        '    .PortOpen = True
        '    If .PortOpen Then
        '        ShowMsg("LED connection successfully")
        '        If m_oERReader.setLedBuzzer(1) = False Then ' let the green led on.
        '            ShowMsg("Port closed. LED operation failed.")
        '        End If
        '        .PortOpen = False
        '    End If
        'End With
ERR_EXIT:
        Exit Sub

ERR_PROC:
        MsgBox("Err.Description=" & Err.Description & "__I=" & I & "_iEventListCount=" & iEventListCount & "_lvEvent.Items.Count=" & lvEvent.Items.Count & "_lvEvent.SelectedItems.Count" & lvEvent.SelectedItems.Count)
    End Sub

    'This function to save .log file.
    Private Sub SaveLog(ByRef oEventItem As ListViewItem)
        Dim sEventLog As String
        Dim sMyDay As String
        Dim sLogFileName As String
        Dim bIsaNewDay As Boolean
        Dim sMyFilePath As String

        sLogFileName = getLogFileName()

        ' check the dir has been existed or not. in win10 must or get the error path not exist.
        If Trim$(Dir$(m_sLogDirPath, vbDirectory)) = "" Then
            MkDir(m_sLogDirPath)
        End If

        sMyFilePath = m_sLogDirPath & sLogFileName

        sEventLog = oEventItem.Text & "," & oEventItem.SubItems(1).Text & "," & oEventItem.SubItems(2).Text
        sMyDay = Format(Now, "dd")
        If m_sToday <> "" Then
            If m_sToday <> sMyDay Then
                m_sToday = sMyDay
                bIsaNewDay = True
            End If
        Else
            m_sToday = sMyDay
            bIsaNewDay = True
        End If

        If bIsaNewDay Then
            Call appendFileTitle(sMyFilePath)
        End If

        ' try..catch is the must when use the WriteAllText function, or get the error in win10.
        Try
            My.Computer.FileSystem.WriteAllText(sMyFilePath, sEventLog & vbCrLf, True)
        Catch ex As Exception
            MsgBox("SaveLog - " & ex.Message)
        End Try

    End Sub

    Private Sub appendFileTitle(ByVal sFilePath As String)
        Dim sString As String

        Try
            sString = "Attendance Records" & "," & "List" & "     " & Now.ToString
            My.Computer.FileSystem.WriteAllText(sFilePath, sString & vbCrLf, True)
            sString = " "
            My.Computer.FileSystem.WriteAllText(sFilePath, sString & vbCrLf, True)
            sString = "Device IP " & "," & "  Date Time" & "," & "Card UID"
            My.Computer.FileSystem.WriteAllText(sFilePath, sString & vbCrLf, True)
            sString = "----------------------------" & "," & "-------------------------------------------" & "," & "--------------------------------"
            My.Computer.FileSystem.WriteAllText(sFilePath, sString & vbCrLf, True)
        Catch ex As Exception
            MsgBox("appendFileTitle - " & ex.Message)
        End Try


    End Sub

    Private Function getLogFileName() As String
        Dim sMyYear As String
        Dim sMyMonth As String
        Dim sLogFileName As String

        sMyYear = Format(Now, "yyyy")
        sMyMonth = Format(Now, "MM")

        sLogFileName = sMyYear & "_" & sMyMonth & ".log"
        getLogFileName = sLogFileName
    End Function

    Private Sub MyTCPListener1_OnDataReceive(ByRef sender As Object, ByVal iBytesToReceive As Integer, ByRef bytDataBuffer() As Byte) Handles MyTCPListener1.OnDataReceive
        Me.BeginInvoke(m_oOnDataReceiveDelegate, sender, iBytesToReceive, bytDataBuffer)
    End Sub

    Private Sub frmMain_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        SaveSetting(APP_TITLE, "Converter", "DateTimeFormat", CStr(cboDateFormat.SelectedIndex))
    End Sub

    Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim MeVersion As String
        Dim UtcOffset As TimeSpan = GIGATMS.TimeZoneInfo.CurrentTimeZone.StandardUtcOffset

        ' show S/W version
        With My.Application.Info.Version
            MeVersion = " V" & .Major & "." & .Minor & "R" & .Revision
        End With
        Me.Text = Me.Text & Space$(3) & MeVersion

        txtListenerIP.Text = MyTCPListener1.getListenerIpAddress_IPv4


        lblTimeZone.Text = UtcOffset.ToString

        cboDateFormat.SelectedIndex = Val(GetSetting(APP_TITLE, "Converter", "DateTimeFormat", "0"))

        'initial Event Server
        Call LinkToListener()

        'initial form's settings
        txtFilePath.Text = m_sLogDirPath
        Call ListAvailableComPorts()
    End Sub

    Private Sub btnReLink_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReLink.Click
        Call LinkToListener()
    End Sub

    Private Sub LinkToListener()
        If MyTCPListener1.IsServerStarted Then
            MyTCPListener1.Close()
        Else
            If MyTCPListener1.Listen(CInt(txtListenerPort.Text)) Then
                ShowMsg("Listen Port " & txtListenerPort.Text & " OK.")
            Else
                ShowMsg("Can't listen this port " & txtListenerPort.Text)
            End If
        End If
    End Sub

    Private Sub lvEvent_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvEvent.DoubleClick
        lvEvent.Columns.Clear()
    End Sub
    Private Sub cboDateFormat_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboDateFormat.SelectedIndexChanged
        m_sDateFormat = cboDateFormat.Text
    End Sub

    Private Sub chkEnablePCtime_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkEnablePCtime.CheckedChanged
        If chkEnablePCtime.Checked Then
            m_bEnablePCtime = True
        Else
            m_bEnablePCtime = False
        End If
    End Sub
    Private Sub txtView_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtView.DoubleClick
        txtView.Clear()
    End Sub

    Private Sub btnClearListView_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClearListView.Click
        lvEvent.Items.Clear()
    End Sub

    Private Sub btnOpenDoor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpenDoor.Click
        Dim bResult As Boolean

        ' using ERReader.dll API control the reader's relay, led and buzzer after read card.
        bResult = OpenDoor()
        'If OpenDoor() = False Then
        If bResult = False Then
            MsgBox("Open door fail.")
        End If
        Call LedBuzzerEffect(bResult)


    End Sub

    Private Sub LedBuzzerEffect(ByVal bIsOpenDoor As Boolean)
        Dim iSeconds As Integer
        iSeconds = CInt(txtDoorOpenTime.Text) * 1000

        If bIsOpenDoor Then
            Call m_oERReader.setLedBuzzer("7") ' #7 = Green LED ON with Beep once.
            Call mDoEventSleep(iSeconds)
            Call m_oERReader.setLedBuzzer("0") ' #0 = Red and Green LED Off, Buzzer Off.
        Else
            Call m_oERReader.setLedBuzzer("8") ' #8 = Red LED ON with Beep 3 Times(process about 3s).

            iSeconds = 3
            Call mDoEventSleep(iSeconds)

            Call m_oERReader.setLedBuzzer("0") ' #0 = Red and Green LED Off, Buzzer Off.
        End If


        '' for lower level(by using GNet.dll) to control the reader's relay, led and buzzer after read card.
        'Dim theDataBuf_action7() As Byte = {2, 74, 55, 13} ' =02H, 4AH, 37H, 0DH
        'Dim theDataBuf_action8() As Byte = {2, 74, 56, 13} ' =02H, 4AH, 38H, 0DH
        'Dim theDataBuf_action0() As Byte = {2, 74, 48, 13} ' =02H, 4AH, 30H, 0DH

        'If bIsOpenDoor Then
        '    If (m_oERReader.PortOpen) Then
        '        m_oERReader.PortOpen = False
        '       Call mDoEventSleep(150)
        '    End If
        '    m_oERReader.PortName = cboCommport.Text
        '    m_oERReader.PortOpen = True

        '    m_oERReader.WriteBuffer(theDataBuf_action7, 1, 4)

        '    Call mDoEventSleep(iSeconds)

        '    m_oERReader.WriteBuffer(theDataBuf_action0, 1, 4)
        'Else
        '    m_oERReader.WriteBuffer(theDataBuf_action8, 1, 4)

        '    iSeconds = 3
        '    Call mDoEventSleep(iSeconds)

        '    m_oERReader.WriteBuffer(theDataBuf_action0, 1, 4)
        'End If

    End Sub

    Private Function OpenDoor() As Boolean
        Dim bResult As Boolean
        Dim sDoorOpenTime As String
        Dim iCount As Integer

        sDoorOpenTime = txtDoorOpenTime.Text
        iCount = Val(sDoorOpenTime)
        If iCount = 0 Then
            OpenDoor = True
            Exit Function
        ElseIf iCount > 255 Then
            iCount = 255
            txtDoorOpenTime.Text = CStr(iCount)
        End If

        If m_oERReader.setRelay(iCount) Then
            bResult = True
        Else
            bResult = False
        End If
        OpenDoor = bResult
    End Function

    Private Sub ListAvailableComPorts()
        Dim szPorts() As String
        m_oERReader = New GIGATMS.ERReader()
        szPorts = m_oERReader.EnumCommPortEx
        cboCommport.Items.AddRange(szPorts)
        m_szEnumPortList = vbNullChar & Join(szPorts, vbNullChar) & vbNullChar

        If cboCommport.Items.Count > 0 Then
            cboCommport.SelectedIndex = 0
        End If
    End Sub

    Private Sub cmdOpenPort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOpenPort.Click
        Dim szPort As String
        'Dim iType As GIGATMS.ERReader.MachineTypeConstants, iReadModal As GIGATMS.ERReader.ReaderModal
        szPort = cboCommport.Text

        If Microsoft.VisualBasic.Left(szPort, 3) = "COM" Or Microsoft.VisualBasic.Left(szPort, 3) = "TCP" Then
            'iType = GIGATMS.ERReader.MachineTypeConstants.Any
            'iReadModal = GIGATMS.ERReader.ReaderModal.Any
            'If m_oERReader.AutoScan(iType, iReadModal, szPort, True) Then
            '    ShowMsg("Connect to " & Replace(szPort, vbCrLf, " "))
            '    lblPortOpenState.BackColor = System.Drawing.Color.Chartreuse
            'Else
            '    MsgBox("Ethernet Reader Connect NG.")
            '    lblPortOpenState.BackColor = System.Drawing.Color.Red
            'End If
            If m_oERReader.ConnectToReader(szPort) Then
                ShowMsg("Connect to " & Replace(szPort, vbCrLf, " "))
                lblPortOpenState.BackColor = System.Drawing.Color.Chartreuse
            Else
                MsgBox("Ethernet Reader Connect NG.")
                lblPortOpenState.BackColor = System.Drawing.Color.Red
            End If
        Else
            MsgBox("Please Select Commport.")
            lblPortOpenState.BackColor = System.Drawing.Color.Red
        End If
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click, Button3.Click, Button2.Click, Button9.Click, Button8.Click, Button7.Click, Button6.Click, Button5.Click, Button4.Click, Button10.Click
        Dim bResult As Boolean
        Dim sButtonCaption As String

        sButtonCaption = DirectCast((sender), Button).Text

        lblLedBuzzerActionDescription.Text = showLedBuzzerActionDescription(sButtonCaption)

        bResult = m_oERReader.setLedBuzzer(sButtonCaption)
        If bResult = False Then
            MsgBox("Set LED/Buzzer NG.")
        End If

    End Sub

    Private Function showLedBuzzerActionDescription(ByVal sNUMBER As String) As String
        Dim sActionDescription As String
        sActionDescription = "No Action."
        Select Case sNUMBER
            Case "0"
                sActionDescription = "Red and Green LED Off, Buzzer Off."
            Case "1"
                sActionDescription = "Green LED ON."
            Case "2"
                sActionDescription = "Green LED OFF."
            Case "3"
                sActionDescription = "Red LED ON."
            Case "4"
                sActionDescription = "Red LED OFF."
            Case "5"
                sActionDescription = "Buzzer Beep once."
            Case "6"
                sActionDescription = "Buzzer Beep 3 Times."
            Case "7"
                sActionDescription = "Green LED ON with Beep once."
            Case "8"
                sActionDescription = "Red LED ON with Beep 3 Times."
            Case "9"
                sActionDescription = "Red and Green LED ON."
        End Select
        showLedBuzzerActionDescription = sActionDescription
    End Function

    Private Sub btnFileDir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFileDir.Click
        Dim FolderBrowserDialog1 As New FolderBrowserDialog

        With FolderBrowserDialog1
            ' Desktop is the root folder in the dialog.
            .RootFolder = Environment.SpecialFolder.Desktop
            ' Select the directory on entry.
            .SelectedPath = m_sLogDirPath
            ' Prompt the user with a custom message.
            .Description = "Select the log file directory"
            If .ShowDialog = Windows.Forms.DialogResult.OK Then
                ' Display the selected folder if the user clicked on the OK button.
                txtFilePath.Text = .SelectedPath
                m_sLogDirPath = txtFilePath.Text.ToString & "\"
            End If
        End With
    End Sub

    Private Sub mDoEventSleep(ByVal seconds As Integer)
        My.Application.DoEvents() ' release CPU usage.
        System.Threading.Thread.Sleep(seconds)
    End Sub

End Class