'
' PDFlib client: invoice generation demo vb.NET
' Required software: PDFlib+PDI or PDFlib Personalization Server (PPS)

Imports System
Imports System.Text
Imports PDFlib_dotnet
Imports Microsoft.VisualBasic
Imports System.Globalization

Structure articledata
    Public name As String
    Public price As Double
    Public quantity As Integer

    ' Constructor:
    Public Sub New(ByVal s_name As String, ByVal s_price As Double, ByVal s_quantity As Integer)
        name = s_name
        price = s_price
        quantity = s_quantity
    End Sub
End Structure


Module invoice


    Public p As PDFlib
    Public x_table As Double = 55
    Public tablewidth As Double = 475

    Public y_address As Double = 682
    Public x_salesrep As Double = 455
    Public y_invoice As Double = 542
    Public imagesize As Double = 90

    Public fontsize As Double = 11
    Public fontsizesmall As Double = 9

    Public fontname As String = "NotoSerif-Regular"


    Public basefontoptions As New StringBuilder

    ' -----------------------------------
    ' Place company stationery as background
    ' -----------------------------------

    Public Sub create_stationery(ByVal p As PDFlib) 

        Dim sender As String = _
            "Kraxi Systems, Inc. &#x2022; 17, Aviation Road &#x2022; Paperfield"
        Dim stationeryfontname As String = "NotoSerif-Regular"

        Dim stationeryfilename As String = "kraxi_logo.pdf"

        Dim y_company_logo As Double = 748

        Dim senderfull As String = _
            "17, Aviation Road\n" & _
            "Paperfield<nextline leading=50%><nextparagraph leading=120%>" & _
            "Phone 7079-4301\n" & _
            "Fax 7079-4302<nextline leading=50%><nextparagraph leading=120%>" & _
            "info@kraxi.com\n" & _
            "www.kraxi.com\n"

        Dim page, stationery, tf As Integer

        Dim optlist As New StringBuilder()

        stationery = p.open_pdi_document(stationeryfilename, "")
        page = p.open_pdi_page(stationery, 1, "")

        p.fit_pdi_page(page, 0, y_company_logo, _
                "boxsize={595 85} position={65 center}")
        p.close_pdi_page(page)
        p.close_pdi_document(stationery)

        optlist.Length = 0
        optlist.AppendFormat("{0} fontsize {1} fontname={2} charref=true", _
            basefontoptions, fontsizesmall, stationeryfontname)
        p.fit_textline(sender, x_table, y_address + fontsize, _
                optlist.ToString())

        ' ---------------------------------
        ' Print full company contact details
        '
        optlist.Length = 0
        optlist.AppendFormat("{0} fontname={1}", basefontoptions, stationeryfontname)
        optlist.Append(" leading=125% fillcolor={cmyk 0.64 0.55 0.52 0.27}")
        tf = p.create_textflow(senderfull, optlist.ToString())
        p.fit_textflow(tf, x_salesrep, y_address, _
                x_salesrep + imagesize, y_address + 150, "verticalalign=bottom")
        p.delete_textflow(tf)
    End Sub

    ' -----------------------------------
    ' Place address and header text
    ' -----------------------------------

    Public Sub create_header(ByVal p As PDFlib)

        Dim salesrepfilename As String = "sales_rep4.jpg"
        Dim salesrepname As String = "Lucy Irwin"
        Dim salesrepcaption As String = "Local sales rep:"
        Dim invoiceheader As String = "INVOICE 2012-03"
        Dim ltime As System.DateTime
        Dim buf As New StringBuilder()


        Dim address As String = _
            "John Q. Doe\n" & _
            "255 Customer Lane\n" & _
            "Suite B\n" & _
            "12345 User Town\n" & _
            "Everland"

        Dim months() As String = {"January", "February", "March", "April", _
                            "May", "June", "July", "August", "September", _
                            "October", "November", "December"}


        Dim optlist As New StringBuilder()
        Dim salesrepimage, tf As Integer


        ' -----------------------------------
        ' Print address
        ' -----------------------------------
        '
        optlist.Length = 0
        optlist.AppendFormat("{0} leading=120%", basefontoptions)

        tf = p.create_textflow(address, optlist.ToString())
        p.fit_textflow(tf, _
                x_table, y_address, x_table + tablewidth / 2, y_address - 100, "")
        p.delete_textflow(tf)

        ' -----------------------------------
        ' Place name and image of local sales rep
        ' -----------------------------------

        optlist.Length = 0
        optlist.AppendFormat("{0} fontsize={1}", basefontoptions, fontsizesmall)
        p.fit_textline(salesrepcaption, x_salesrep, y_address - fontsizesmall, _
                optlist.ToString())
        p.fit_textline(salesrepname, x_salesrep, y_address - 2 * fontsizesmall, _
                optlist.ToString())

        salesrepimage = p.load_image("auto", salesrepfilename, "")

        optlist.Length = 0
        optlist.Append("boxsize={")
        optlist.AppendFormat("{0} {1}", imagesize, imagesize)
        optlist.Append("} fitmethod=meet")
        p.fit_image(salesrepimage, _
                x_salesrep, y_address - 3 * fontsizesmall - imagesize, optlist.ToString())
        p.close_image(salesrepimage)

        ' -----------------------------------
        ' Print the header and date
        ' -----------------------------------


        ' Add a bookmark with the header text 
        p.create_bookmark(invoiceheader, "")

        ' optlist =  basefontoptions
        p.fit_textline(invoiceheader, x_table, y_invoice, basefontoptions.ToString())

        ltime = System.DateTime.Now
        buf.Length = 0
        buf.AppendFormat("{0} {1}, {2}", months(ltime.Month - 1), ltime.Day, ltime.Year)

        optlist.Length = 0
        optlist.Append("position {100 0} ")
        optlist.AppendFormat("{0}", basefontoptions)

        p.fit_textline(buf.ToString(), x_table + tablewidth, y_invoice, optlist.ToString())
    End Sub

    Public Sub Main()
        Dim p As PDFlib = Nothing
        ' This is where font/image/PDF input files live. Adjust as necessary.
        Dim searchpath As String = "../../../data"

        ' By default annotations are also imported. In some cases this
        ' requires the Noto fonts for creating annotation appearance streams.
        ' We therefore set the searchpath to also point to the font directory.
        '
        Dim fontpath = "../../../../resource/font"

        Dim baseopt As String = _
                "ruler        {   30 45     275   375   475} " & _
                "tabalignment {right left right right right} " & _
                "hortabmethod ruler fontsize 12 "

        Dim closingtext As String = _
            "Terms of payment: <fillcolor={rgb 1 0 0}>30 days net. " & _
            "<fillcolor={gray 0}>90 days warranty starting at the day of sale. " & _
            "This warranty covers defects in workmanship only. " & _
            "Kraxi Systems, Inc. will, at its option, repair or replace the " & _
            "product under the warranty. This warranty is not transferable. " & _
            "No returns or exchanges will be accepted for wet products."

        Dim dataset(6) As articledata
        dataset(0) = New articledata("Super Kite", 20, 2)
        dataset(1) = New articledata("Turbo Flyer", 40, 5)
        dataset(2) = New articledata("Giga Trash", 180, 1)
        dataset(3) = New articledata("Bare Bone Kit", 50, 3)
        dataset(4) = New articledata("Nitty Gritty", 20, 10)
        dataset(5) = New articledata("Pretty Dark Flyer", 75, 1)
        dataset(6) = New articledata("Free Gift", 0, 1)


        Dim headers() As String = { _
            "ITEM", "DESCRIPTION", "QUANTITY", "PRICE", "AMOUNT" _
        }

        Dim alignments() As String = { _
            "right", "left", "right", "right", "right" _
        }

        Try
            p = New PDFlib()

            Dim pagecount As Integer = 0
            Dim i, row, col, tbl, tf As Integer
            Dim result As String
            Dim total As Double
            Dim buf As New StringBuilder()
            Dim optlist As New StringBuilder()

            Dim culture As New CultureInfo("en-US")

            optlist.Length = 0
            optlist.Append("SearchPath={{")
            optlist.AppendFormat("{0}", searchpath)
            optlist.Append("}}")
            p.set_option(optlist.ToString())

            optlist.Length = 0
            optlist.Append("SearchPath={{")
            optlist.AppendFormat("{0}", fontpath)
            optlist.Append("}}")
            p.set_option(optlist.ToString())

            ' This mean we don't have to check error return values, but will
            ' get an exception in case of runtime problems.

            p.set_option("errorpolicy=exception escapesequence")

            p.begin_document("invoice.pdf", "")

            p.set_info("Creator", "invoice")
            p.set_info("Author", "Thomas Merz")
            p.set_info("Title", "PDFlib invoice generation demo")

            basefontoptions.Length = 0
            basefontoptions.AppendFormat("fontname={0} fontsize= {1}", _
                fontname, fontsize)

            ' -----------------------------------
            ' Create and place table with article list
            ' -----------------------------------

            ' ---------- Header row 
            row = 1
            tbl = -1

            For col = 1 To headers.Length

                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions.ToString())
                optlist.Append("} margin=2")
                tbl = p.add_table_cell(tbl, col, row, headers(col - 1), _
                optlist.ToString())
            Next
            row = row + 1

            ' ---------- Data rows: one for each article 
            total = 0

            For i = 0 To dataset.Length - 1
                Dim sum As Double = dataset(i).price * dataset(i).quantity
                col = 1

                ' column 1: ITEM
                buf.Length = 0
                buf.AppendFormat("{0}", (i + 1))

                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions.ToString())
                optlist.Append("} margin=2")
                tbl = p.add_table_cell(tbl, col, row, buf.ToString(), optlist.ToString())
                col = col + 1

                ' column 2: DESCRIPTION 
                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions.ToString())
                optlist.Append("} colwidth=50% margin=2")
                tbl = p.add_table_cell(tbl, col, row, dataset(i).name, _
                        optlist.ToString())
                col = col + 1

                ' column 3: QUANTITY 
                buf.Length = 0
                buf.AppendFormat("{0}", dataset(i).quantity)

                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions)
                optlist.Append("} margin=2")
                tbl = p.add_table_cell(tbl, col, row, buf.ToString(), optlist.ToString())
                col = col + 1

                ' column 4: PRICE 
                buf.Length = 0
                buf.AppendFormat(culture, "{0:F2}", dataset(i).price)

                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions)
                optlist.Append("} margin=2")
                tbl = p.add_table_cell(tbl, col, row, buf.ToString(), optlist.ToString())
                col = col + 1

                ' column 5: AMOUNT 
                buf.Length = 0
                buf.AppendFormat(culture, "{0:F2}", sum)

                optlist.Length = 0
                optlist.Append("fittextline={position={")
                optlist.AppendFormat("{0} ", alignments(col - 1))
                optlist.Append("center} ")
                optlist.AppendFormat("{0}", basefontoptions)
                optlist.Append("} margin=2")
                tbl = p.add_table_cell(tbl, col, row, buf.ToString(), optlist.ToString())
                col = col + 1

                total += sum
                row = row + 1
            Next

            ' ---------- Print total in the rightmost column 
            buf.Length = 0
            buf.AppendFormat(culture, "{0:F2}", total)

            optlist.Length = 0
            optlist.Append("fittextline={position={")
            optlist.AppendFormat("{0} ", alignments(headers.Length - 1))
            optlist.Append("center} ")
            optlist.AppendFormat("{0}", basefontoptions.ToString())
            optlist.Append("} margin=2")
            tbl = p.add_table_cell(tbl, headers.Length, row, buf.ToString(), optlist.ToString())
            row = row + 1

            ' ---------- Footer row with terms of payment 

            optlist.Length = 0
            optlist.AppendFormat("{0} alignment=justify leading=120%", basefontoptions.ToString())
            tf = p.create_textflow(closingtext, optlist.ToString())

            optlist.Length = 0
            optlist.AppendFormat("rowheight=1 margin=2 margintop={0} textflow={1} colspan={2}",
            2 * fontsize, tf, headers.Length)

            tbl = p.add_table_cell(tbl, 1, row, "", optlist.ToString())


            ' ---------- Place the table instance(s), creating pages as required 
            Do
                Dim top As Double

                p.begin_page_ext(0, 0, "width=a4.width height=a4.height")

                pagecount = pagecount + 1

                If pagecount = 1 Then

                    create_stationery(p)
                    create_header(p)
                    top = y_invoice - 3 * fontsize

                Else

                    top = 50
                End If

                ' Place the table on the page; Shade every other row. 
                optlist.Length = 0
                optlist.Append("header=1 fill={{area=rowodd fillcolor={gray 0.9}}} ")

                result = p.fit_table(tbl,
                        x_table, top, x_table + tablewidth, 20, optlist.ToString())

                If result = "_error" Then
                    Console.WriteLine("Couldn't place table: " & p.get_errmsg())
                    Return

                End If

                p.end_page_ext("")
            Loop While result = "_boxfull"

            p.delete_table(tbl, "")

            p.end_document("")


        Catch e As PDFlibException
            ' caught exception thrown by PDFlib
            Console.WriteLine("PDFlib exception occurred in invoice sample:")
            Console.WriteLine("[{0}] {1}: {2}", e.get_errnum(), e.get_apiname(), e.get_errmsg)

        Finally
            If Not p Is Nothing Then
                p.Dispose()
            End If
        End Try

    End Sub
End Module
