Imports System.Text
Imports dxp01sdk

Namespace SmartcardCommonNamespace
    Public Class SmartcardCommon
        Public Shared Sub DisplayProtocols(protocol As UInteger)
            Dim protocols As String() = SCard.StringsFromProtocol(protocol)
            Console.Write("   protocol[s]: ")
            For index As Integer = 0 To protocols.Length - 1
                Console.Write(protocols(index) + " ")
            Next
            Console.WriteLine()
        End Sub

        Public Shared Sub DisplayByteVectorAsHex(ByVal title As String, ByVal receivedBytes As Byte())
            Console.Write("{0}:", title)

            For index As Integer = 0 To receivedBytes.Length - 1
                Console.Write("{0:X02} ", receivedBytes(index))
            Next

            Console.WriteLine()
        End Sub

        Public Shared Sub ParkCard(bidiSpl As BidiSplWrap, parkBack As Boolean)
            Dim parkCommand As String = If(parkBack, strings.SMARTCARD_PARK_BACK, strings.SMARTCARD_PARK)
            Dim printerStatusXML As String = bidiSpl.SetPrinterData(parkCommand)
            Dim printerStatusValues As PrinterStatusValues = Util.ParsePrinterStatusXML(printerStatusXML)
            If 0 <> printerStatusValues._errorCode Then
                Throw New Exception("SmartcardPark(): " + printerStatusValues._errorString)
            End If
        End Sub

        Public Shared Sub ResumeCard(bidiSpl As BidiSplWrap, printerJobID As Integer, errorCode As Integer)
            Dim xmlFormat As String = strings.PRINTER_ACTION_XML
            Dim input As String = String.Format(xmlFormat, CInt(Actions.[Resume]), printerJobID, errorCode)
            Console.WriteLine("issuing Resume after smartcard:")
            bidiSpl.SetPrinterData(strings.PRINTER_ACTION, input)
        End Sub

        Public Shared Function SCardResultMessage(scardResult As Long, message As String) As String
            Dim sb As StringBuilder = New StringBuilder()
            sb.Append(message)
            sb.Append(" result: ")
            sb.Append(scardResult.ToString())
            sb.Append("; ")
            sb.Append(Util.Win32ErrorString(CUInt(scardResult)))
            Return sb.ToString()
        End Function

        Public Shared Sub GetSCardStatus(scard As SCard)
            Dim states As Integer() = New Integer(-1) {}
            Dim protocol As UInteger = CUInt(scard_protocol.SCARD_PROTOCOL_DEFAULT)
            Dim ATRBytes As Byte() = New Byte(-1) {}
            Dim scardResult As Long = scard.SCardStatus(states, protocol, ATRBytes)

            Console.WriteLine("SCardStatus result: {0}: {1}", scardResult, Util.Win32ErrorString(CUInt(scardResult)))
            If CLng(scard_error.SCARD_S_SUCCESS) <> scardResult Then
                Dim msg As String = SCardResultMessage(scardResult, "")
                Throw New Exception("SCardStatus() fail: " & msg)
            End If

            ' display all the 'states' returned. if ANY of the states is SCARD_ABSENT -
            ' we are done with this card.
            Dim cardAbsent As Boolean = False
            Console.Write("SCardStatus() states: ")
            For index As Integer = 0 To states.Length - 1
                Console.Write(states(index))
                Console.Write(" ")
                Console.Write(SCard.StringFromState(states(index)))
                Console.Write(" ")

                If scard_state.SCARD_ABSENT = DirectCast(states(index), scard_state) Then
                    cardAbsent = True
                End If
            Next
            Console.WriteLine()

            If cardAbsent Then
                Throw New Exception("one of the states is SCARD_ABSENT.")
            End If

            Console.Write("SCardStatus() ATR: ")
            Console.WriteLine(Bytes_to_HEX_String(ATRBytes))
        End Sub

        Public Shared Function Bytes_to_HEX_String(bytes As Byte()) As String
            Dim sb As StringBuilder = New StringBuilder()
            For Each b As Byte In bytes
                sb.Append(String.Format("{0:X02} ", b))
            Next
            Return sb.ToString()
        End Function


        Public Shared Function ReadVendorInfo(ByVal scard As SCard) As Boolean
            Dim attributesToTry As scard_attr() = New scard_attr() {scard_attr.SCARD_ATTR_VENDOR_NAME, scard_attr.SCARD_ATTR_VENDOR_IFD_SERIAL_NO, scard_attr.SCARD_ATTR_VENDOR_IFD_TYPE, scard_attr.SCARD_ATTR_VENDOR_IFD_VERSION}

            For attribIndex As Integer = 0 To attributesToTry.Length - 1
                Dim scardAttributeBytes As Byte() = New Byte(-1) {}

                Dim scardResult As Long = scard.SCardGetAttrib(attributesToTry(attribIndex), scardAttributeBytes)

                If CLng(scard_error.SCARD_S_SUCCESS) <> scardResult Then
                    Continue For
                End If

                Dim msg As String = String.Format("SCardGetAttrib({0})", SCard.StringFromAttr(CInt(attributesToTry(attribIndex))))
                Console.WriteLine(SCardResultMessage(scardResult, msg))

                Select Case attributesToTry(attribIndex)
                    Case scard_attr.SCARD_ATTR_VENDOR_IFD_VERSION
                        ' vendor-supplied interface device version: DWORD in the form 0xMMmmbbbb where
                        '      MM = major version;
                        '      mm = minor version; and
                        '      bbbb = build number:
                        Dim byteCount As Integer = scardAttributeBytes.Length
                        Dim minorVersion As Integer = If(byteCount > 0, scardAttributeBytes(0), 0)
                        Dim majorVersion As Integer = If(byteCount > 1, scardAttributeBytes(1), 0)
                        Dim buildNumber As Integer = 0
                        If byteCount > 3 Then
                            buildNumber = (scardAttributeBytes(2) << 8) + scardAttributeBytes(3)
                        End If

                        Console.WriteLine("SCARD_ATTR_VENDOR_IFD_VERSION:")
                        Console.Write("    major: " & majorVersion.ToString())
                        Console.Write("    minor: " & minorVersion.ToString())
                        Console.WriteLine("    build: " & buildNumber.ToString())
                        Exit Select
                    Case Else

                        ' null-terminate the returned byte for string display.
                        Dim bytesList As List(Of Byte) = New List(Of Byte)(scardAttributeBytes)
                        bytesList.Add(0)
                        scardAttributeBytes = bytesList.ToArray()
                        Console.WriteLine(ASCIIEncoding.UTF8.GetString(scardAttributeBytes))
                        Exit Select
                End Select
            Next
            Return True
        End Function
    End Class
End Namespace