''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright (c) Datacard Corporation.  All Rights Reserved.
'
' XPS Printer SDK: vb.net 'printer_control' sample
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Imports System.IO
Imports dxp01sdk

Public Enum Commands
    undefined
    cancelAllJobs
    restart
    resetCardCounts
    adjustColors
    defaultColors
    powerDownPrinter
    cleanLaminator
    cleanPrinter
    setColorMode
    wakePrinter
    sleepPrinter
End Enum

Public Class CommandLineOptions
    Public Sub New()
        command = Commands.undefined
    End Sub
    Public printerName As String
    Public command As Commands
    Public colorMode As String
End Class

Class control
    Private Shared SigmaColormodeValues As List(Of String) = New List(Of String) From {
        "TrueColor (ICC)", "Vivid", "SD/CD", "Custom"}
    Private Shared CR805ColormodeValues As List(Of String) = New List(Of String) From {
        "TrueColor (ICC)", "Vivid", "Legacy SR/CR", "Legacy SR wLUT", "Adobe RGB"}

    Private Shared Sub Usage()
        Dim thisExeName As String = Path.GetFileName(Environment.GetCommandLineArgs()(0))
        Console.WriteLine()
        Console.WriteLine(thisExeName & " controls the printer through the printer driver.")
        Console.WriteLine()
        Console.WriteLine(thisExeName & " -n <printername> <command>")
        Console.WriteLine("  -n <printername>. Required. Try -n ""XPS Card Printer"".")
        Console.WriteLine("  -c cancel all jobs: Send a command to the printer to clear any print job")
        Console.WriteLine("                    from the printer. This does not delete spooled Windows")
        Console.WriteLine("                    print jobs.")
        Console.WriteLine("  -p power down the printer.")
        Console.WriteLine("  -q clean the printer.")
        Console.WriteLine("  -r restart the printer.")
        Console.WriteLine("  -w wake the printer.")
        Console.WriteLine("  -s put the printer to sleep.")
        Console.WriteLine("  -e reset all card counts.")
        Console.WriteLine("  -a set colorAdjust settings. This sample changes only the Red settings. Blue and Green are unchanged")
        Console.WriteLine("  -d set default colorAdjust settings. This sample only resets Red and Green.  Blue is unchanged.")
        Console.WriteLine("  -s set colorMode <colorMode>")
        Console.WriteLine()
        Environment.Exit(-1)
    End Sub

    Private Shared Function GetCommandlineOptions(args As String()) As CommandLineOptions
        Dim commandLineOptions As New CommandLineOptions()
        Dim arguments As New CommandLine.Utility.Arguments(args)

        If String.IsNullOrEmpty(arguments("n")) Then
            Usage()
        End If

        ' check for -n with no printer name:
        Dim boolVal As Boolean = False
        If Boolean.TryParse(arguments("n"), boolVal) Then
            Usage()
        End If
        commandLineOptions.printerName = arguments("n")

        If Not String.IsNullOrEmpty(arguments("c")) Then
            commandLineOptions.command = Commands.cancelAllJobs
        End If

        If Not String.IsNullOrEmpty(arguments("p")) Then
            commandLineOptions.command = Commands.powerDownPrinter
        End If

        If Not String.IsNullOrEmpty(arguments("q")) Then
            commandLineOptions.command = Commands.cleanPrinter
        End If

        If Not String.IsNullOrEmpty(arguments("r")) Then
            commandLineOptions.command = Commands.restart
        End If

        If Not String.IsNullOrEmpty(arguments("e")) Then
            commandLineOptions.command = Commands.resetCardCounts
        End If

        If Not String.IsNullOrEmpty(arguments("a")) Then
            commandLineOptions.command = Commands.adjustColors
        End If

        If Not String.IsNullOrEmpty(arguments("d")) Then
            commandLineOptions.command = Commands.defaultColors
        End If

        If Not String.IsNullOrEmpty(arguments("s")) Then
            commandLineOptions.command = Commands.setColorMode
            commandLineOptions.colorMode = arguments("s")
        End If

        If Not String.IsNullOrEmpty(arguments("w")) Then
            commandLineOptions.command = Commands.wakePrinter
        End If

        If Not String.IsNullOrEmpty(arguments("x")) Then
            commandLineOptions.command = Commands.sleepPrinter
        End If

        If Commands.undefined = commandLineOptions.command Then
            Usage()
        End If

        Return commandLineOptions
    End Function


    Public Shared Sub adjustColors(bidiSpl As BidiSplWrap)
        ' create the XML and convert to bytes for the upcoming SetInputData() call.

        Dim formattedColorForRChannel As [String] = String.Format(strings.COLOR_CHANNEL, "1", "2", "-1", "0", "25",
        "6", "-19", "12", "13", "14", "15")

        Dim adjustColorXML As [String] = String.Format(strings.ADJUST_COLOR_XML, formattedColorForRChannel, "", "")

        Dim printerStatusXML As String = bidiSpl.SetPrinterData(strings.ADJUST_COLOR, adjustColorXML)
        Dim printerStatusValues As PrinterStatusValues = Util.ParsePrinterStatusXML(printerStatusXML)

        If 0 <> printerStatusValues._errorCode Then
            Console.WriteLine("Request Not supported - error={0}", printerStatusValues._errorCode)
            Throw New BidiException(printerStatusValues._errorString, printerStatusValues._printerJobID, printerStatusValues._errorCode)
        End If
    End Sub

    Public Shared Sub SetDefaultColors(bidiSpl As BidiSplWrap)
        ' create the XML and convert to bytes for the upcoming SetInputData() call.
        ' Setting red and green color channel values back to defaults and keeping blue unchanged
        Dim defaultColorXML As [String] = String.Format(strings.DEFAULT_COLOR_XML, "true", "true", "false")

        Dim printerStatusXML As String = bidiSpl.SetPrinterData(strings.SET_DEFAULT_COLOR, defaultColorXML)
        Dim printerStatusValues As PrinterStatusValues = Util.ParsePrinterStatusXML(printerStatusXML)

        If 0 <> printerStatusValues._errorCode Then
            Console.WriteLine("Request Not supported - error={0}", printerStatusValues._errorCode)
            Throw New BidiException(printerStatusValues._errorString, printerStatusValues._printerJobID, printerStatusValues._errorCode)
        End If
    End Sub



    Public Shared Function isPrinterReady(bidiSpl As BidiSplWrap) As Boolean

        Dim printerOptionsXML As String = bidiSpl.GetPrinterData(strings.PRINTER_OPTIONS2)
        Dim printerOptionsValues As PrinterOptionsValues = Util.ParsePrinterOptionsXML(printerOptionsXML)

        Console.WriteLine("printer state: {0}", printerOptionsValues._printerStatus)

        ' verify that the printer is in the READY state
        If "Ready" <> printerOptionsValues._printerStatus Then
            Throw New Exception("ERROR:  printer is not in state 'READY'.")
        End If

        Return True
    End Function



    Public Shared Function isColorAdjustCapable(bidiSpl As BidiSplWrap) As Boolean

        Dim printerOptionsXML As String = bidiSpl.GetPrinterData(strings.PRINTER_OPTIONS2)
        Dim printerOptionsValues As PrinterOptionsValues = Util.ParsePrinterOptionsXML(printerOptionsXML)

        Console.WriteLine("printer state: {0}", printerOptionsValues._printerStatus)

        ' verify that the printer is in the READY state
        If "Ready" <> printerOptionsValues._printerStatus Then
            Throw New Exception("ERROR:  printer is not in state 'READY'.")
        End If

        Dim strPrinterVersion As String = printerOptionsValues._printerVersion
        Dim actualFirmware As FirmwareVersion = Util.ParseFirmwareRev(strPrinterVersion)
        Console.WriteLine("Printer Version = {0}", strPrinterVersion)

        If (actualFirmware._printerBase = "D3") AndAlso (actualFirmware._majorVersion > 16) Then
            If actualFirmware._majorVersion > 17 Then
                Return True
            ElseIf (actualFirmware._majorVersion = 17) AndAlso (actualFirmware._minorVersion >= 4) Then
                Return True
            End If
        ElseIf (actualFirmware._printerBase = "D4") Then
            Return True
        End If

        Throw New Exception("ERROR - Requires printer version: D3.17.4 (or greater)")
    End Function



    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' isLaminatorPresent()
    '
    ' Returns true if printer Is in READY state And laminator != "none"
    ' otherwise returns false.
    '
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Function isLaminatorPresent(ByVal bidiSpl As BidiSplWrap) As Boolean
        Dim printerOptionsXML As String = bidiSpl.GetPrinterData(strings.PRINTER_OPTIONS2)
        Dim printerOptionsValues As PrinterOptionsValues = Util.ParsePrinterOptionsXML(printerOptionsXML)
        Console.WriteLine("printer state: {0}", printerOptionsValues._printerStatus)

        If "Ready" <> printerOptionsValues._printerStatus Then
            Throw New Exception("ERROR:  printer is not in state 'READY'.")
        End If

        If "None" = printerOptionsValues._laminator Then
            Throw New Exception("ERROR:  printer does not have a laminator.")
        End If

        Return True
    End Function



    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' getPrinterMessage()
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Function getPrinterMessage(ByVal bidiSpl As BidiSplWrap, ByRef errorString As String) As Integer
        Dim errorCode As Integer = 0
        errorString = ""
        Dim count As Integer = 5

        For i As Integer = 0 To count - 1
            Dim printerStatusXML As String = bidiSpl.GetPrinterData(strings.PRINTER_MESSAGES)
            Dim printerStatusValues As PrinterStatusValues = Util.ParsePrinterStatusXML(printerStatusXML)
            errorCode = printerStatusValues._errorCode
            errorString = printerStatusValues._errorString

            If errorCode <> 0 Then
                Exit For
            End If

            If i < count Then
                Threading.Thread.Sleep(1000)
            End If
        Next

        Return errorCode
    End Function


    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' processCleaningCardErrorCode()
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Sub processCleaningCardErrorCode(ByVal bidiSpl As BidiSplWrap, ByVal errorCode As Integer, ByVal errorString As String)
        Select Case errorCode
            Case 0
                Console.WriteLine(" - Did not get proper return code from driver")
                Util.CancelJob(bidiSpl, 0, 0)
            Case 172
                Console.WriteLine(" - Insert Cleaning card.")
            Case Else
                Console.WriteLine("CleanPrinter: {0}", errorString)
                Util.CancelJob(bidiSpl, 0, 0)
        End Select
    End Sub


    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' cleanPrinter()
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Sub cleanPrinter(ByVal bidiSpl As BidiSplWrap)
        Try

            If isPrinterReady(bidiSpl) Then
                bidiSpl.SetPrinterData(strings.CLEAN_PRINTER_ACTION)
                Console.WriteLine("command issued to clean printer.")

                Dim errorString As String = ""
                Dim errorCode As Integer = getPrinterMessage(bidiSpl, errorString)
                processCleaningCardErrorCode(bidiSpl, errorCode, errorString)
            End If

        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try

        Return
    End Sub


    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' cleanLaminator()
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Sub cleanLaminator(ByVal bidiSpl As BidiSplWrap)
        Try

            If isLaminatorPresent(bidiSpl) Then
                bidiSpl.SetPrinterData(strings.CLEAN_LAMINATOR_ACTION)
                Console.WriteLine("command issued to clean laminator.")

                Dim errorString As String = ""
                Dim errorCode As Integer = getPrinterMessage(bidiSpl, errorString)
                processCleaningCardErrorCode(bidiSpl, errorCode, errorString)
            End If

        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try

        Return
    End Sub


    Public Shared Function isColorModeCapable(ByVal bidiSpl As BidiSplWrap, ByVal colorMode As String) As Boolean
        Dim printerOptionsXML As String = bidiSpl.GetPrinterData(strings.PRINTER_OPTIONS2)
        Dim printerOptionsValues As PrinterOptionsValues = Util.ParsePrinterOptionsXML(printerOptionsXML)
        Console.WriteLine("printer state: {0}", printerOptionsValues._printerStatus)

        If "Ready" <> printerOptionsValues._printerStatus Then
            Throw New Exception("ERROR:  printer is not in state 'READY'.")
        End If

        Dim strPrinterVersion As String = printerOptionsValues._printerVersion
        Dim actualFirmware As FirmwareVersion = Util.ParseFirmwareRev(strPrinterVersion)
        Console.WriteLine("Printer Version = {0}", strPrinterVersion)
        Dim bFound As Boolean = False
        Dim exceptionText As String = ""

        If actualFirmware._printerBase = "D4" Then

            For i As Integer = 0 To control.SigmaColormodeValues.Count - 1

                If colorMode = SigmaColormodeValues(i) Then
                    bFound = True
                    Exit For
                End If
            Next

            If Not bFound Then
                exceptionText = "Error - '" & colorMode & "' is not a valid Sigma colormode value"
                Throw New Exception(exceptionText)
            End If
        ElseIf actualFirmware._printerBase = "R4" Then

            For i As Integer = 0 To control.CR805ColormodeValues.Count - 1

                If colorMode = CR805ColormodeValues(i) Then
                    bFound = True
                    Exit For
                End If
            Next

            If Not bFound Then
                exceptionText = "Error - '" & colorMode & "' is not a valid Sigma colormode value"
                Throw New Exception(exceptionText)
            End If
        Else
            exceptionText = "Error - printer type '" & actualFirmware._printerBase & "' does not support colormode"
            Throw New Exception(exceptionText)
        End If

        Return True
    End Function

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    ' setColorMode()
    '
    'using the IBidiSpl interface, issue a 'setColorMode' command.
    '
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''    
    Public Shared Sub setColorMode(ByVal bidiSpl As BidiSplWrap, ByVal colorMode As String)
        Try
            ' this method throws an exception if a problem was incurred
            ' no need to check return code
            isColorModeCapable(bidiSpl, colorMode)

            Dim settingSubsystem As String = "Print"
            Dim settingName As String = "ColorMode"
            Console.WriteLine("command issued to set color mode.")
            Console.WriteLine("    settingSubsystem = {0}.", settingSubsystem)
            Console.WriteLine("    settingName = {0}.", settingName)
            Console.WriteLine("    value = {0}.", colorMode)
            Dim submitSettingsXML As String = String.Format(strings.SUBMIT_SETTINGS_XML, settingSubsystem, settingName, colorMode)
            Dim printerStatusXML As String = bidiSpl.SetPrinterData(strings.SUBMIT_SETTINGS, submitSettingsXML)
        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try
    End Sub

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' Main()
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Public Shared Sub Main(args As String())
        Try
            Dim commandLineOptions As CommandLineOptions = GetCommandlineOptions(args)

            Dim bidiSpl As New BidiSplWrap()
            bidiSpl.BindDevice(commandLineOptions.printerName)

            ' There Is a bug in SendRecv interface. Driver does Not get the correct printer name
            ' if user renames the printer. We mimic sending data to driver And that makes sure that
            ' driver updates the printer name.
            '
            Util.RawDataToXpsPrinter(commandLineOptions.printerName)

            Select Case commandLineOptions.command
                Case Commands.cancelAllJobs
                    ' using zero for the printerJobID and the errorCode causes all
                    ' printerJobs to be canceled:
                    Util.CancelJob(bidiSpl, 0, 0)
                    Console.WriteLine("all jobs canceled for '{0}'", commandLineOptions.printerName)
                    Exit Select

                Case Commands.restart
                    Dim result As String = bidiSpl.SetPrinterData(strings.RESTART_PRINTER)
                    Console.WriteLine("command issued to restart the printer.")
                    Exit Select

                Case Commands.powerDownPrinter
                    Dim result As String = bidiSpl.SetPrinterData(strings.POWER_DOWN_PRINTER)
                    Console.WriteLine("command issued to power down the printer.")
                    Exit Select

                Case Commands.cleanPrinter
                    cleanPrinter(bidiSpl)
                    Exit Select

                Case Commands.cleanLaminator
                    cleanLaminator(bidiSpl)
                    Exit Select

                Case Commands.resetCardCounts
                    Dim result As String = bidiSpl.SetPrinterData(strings.RESET_CARD_COUNTS)
                    Console.WriteLine("command issued to reset the printer's card counts.")
                    Exit Select

                Case Commands.adjustColors
                    Console.WriteLine("AdjustColors - begin.")
                    If isColorAdjustCapable(bidiSpl) Then
                        adjustColors(bidiSpl)
                    End If
                    Console.WriteLine("AdjustColors - end.")
                    Exit Select

                Case Commands.defaultColors
                    Console.WriteLine("SetDefaultColors - begin.")
                    If isColorAdjustCapable(bidiSpl) Then
                        SetDefaultColors(bidiSpl)
                    End If
                    Console.WriteLine("SetDefaultColors - end.")
                    Exit Select

                Case Commands.setColorMode
                    setColorMode(bidiSpl, commandLineOptions.colorMode)
                    Exit Select

                Case Commands.wakePrinter
                    Dim result As String = bidiSpl.SetPrinterData(strings.WAKE_PRINTER)
                    Console.WriteLine("command issued to wake the printer.")
                    Exit Select

                Case Commands.sleepPrinter
                    Dim result As String = bidiSpl.SetPrinterData(strings.SLEEP_PRINTER)
                    Console.WriteLine("command issued to put the printer to sleep.")
                    Exit Select

                Case Else
                    Console.WriteLine("unexpected commandline option.")
                    Exit Select

            End Select

            bidiSpl.UnbindDevice()

        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try


        ' press any key to continue
        Console.WriteLine("Press any key to continue...")
        Console.ReadKey()

    End Sub
End Class
