' IdCodeMaxCode128Demo -- Crystal Reports Custom Function (Basic Syntax)
'
' Runs entirely inside Crystal Reports itself, so it is 100% independent of
' the data source -- SQL Server, Oracle, or anything else Crystal can bind a
' field to. This is what makes the technique "not care which database is
' used", the same way the IDAutomation Crystal integration works: the encoding
' happens in the report engine, not in the database engine.
'
' DEMO VERSION -- prepends "DEMO-" to the input before encoding, so the
' resulting barcode always differs from the real customer data. See
' IdCodeMaxCode128.txt for the full (unprefixed) version.
'
' Faithful port of IdCodeMax.Barcodes.Encoding.Code128Encoder (C#), same
' logic already verified twice: once end-to-end with a real barcode reader
' (docs/CrystalReports-Integration.md §5), and once by hand-tracing the
' identical algorithm for the PL/SQL port (oracle/idcodemax_barcodes_pkg.sql)
' -- both produced the exact same 16 character codes for "IDCODEMAX-2026".
'
' Render the result with the "IdCodeMax Code128" font (installer/IdCodeMax-BarcodeFonts-Setup.msi).
' Usage in a formula: IdCodeMaxCode128Demo({YourTable.YourField})

Function IdCodeMaxCode128Demo (value As String) As String
    Dim i As Number
    Dim n As Number
    Dim mini As Number
    Dim dummy As Number
    Dim checksum As Number
    Dim charsetB As Boolean
    Dim result As String
    Dim pos As Number
    Dim c As Number

    value = "DEMO-" & value
    n = Len(value)
    If n = 0 Then
        IdCodeMaxCode128Demo = ""
        Exit Function
    End If

    For i = 1 To n
        c = Asc(Mid(value, i, 1))
        If c < 32 Or c > 126 Then
            IdCodeMaxCode128Demo = ""
            Exit Function
        End If
    Next

    result = ""
    charsetB = True
    i = 1

    Do While i <= n
        If charsetB Then
            If i = 1 Or i + 3 = n Then
                mini = 4
            Else
                mini = 6
            End If
            mini = mini - 1

            If i + mini <= n Then
                Do While mini >= 0
                    If Asc(Mid(value, i + mini, 1)) < 48 Or Asc(Mid(value, i + mini, 1)) > 57 Then
                        Exit Do
                    End If
                    mini = mini - 1
                Loop
            End If

            If mini < 0 Then
                If i = 1 Then
                    result = result & Chr(210)
                Else
                    result = result & Chr(204)
                End If
                charsetB = False
            Else
                If i = 1 Then
                    result = result & Chr(209)
                End If
            End If
        End If

        If Not charsetB Then
            mini = 1
            If i + mini <= n Then
                Do While mini >= 0
                    If Asc(Mid(value, i + mini, 1)) < 48 Or Asc(Mid(value, i + mini, 1)) > 57 Then
                        Exit Do
                    End If
                    mini = mini - 1
                Loop
            End If

            If mini < 0 Then
                dummy = Val(Mid(value, i, 2))
                If dummy < 95 Then
                    dummy = dummy + 32
                Else
                    dummy = dummy + 105
                End If
                result = result & Chr(dummy)
                i = i + 2
            Else
                result = result & Chr(205)
                charsetB = True
            End If
        End If

        If charsetB Then
            result = result & Mid(value, i, 1)
            i = i + 1
        End If
    Loop

    checksum = 0
    For pos = 1 To Len(result)
        dummy = Asc(Mid(result, pos, 1))
        If dummy < 127 Then
            dummy = dummy - 32
        Else
            dummy = dummy - 105
        End If
        If pos = 1 Then
            checksum = dummy
        End If
        checksum = (checksum + (pos - 1) * dummy) Mod 103
    Next

    If checksum < 95 Then
        checksum = checksum + 32
    Else
        checksum = checksum + 105
    End If

    result = result & Chr(checksum) & Chr(211)
    IdCodeMaxCode128Demo = result
End Function
