//
// PDFlib/PDI client: invoice generation demo in C#
// Required software: PDFlib+PDI or PDFlib Personalization Server (PPS)
//

using System;
using System.Text;
using PDFlib_dotnet;
using System.Globalization;

struct articledata 
{


    public string name;
    public float price;
    public int quantity;

    // Constructor:
    public articledata(string name, float price, int quantity) 
    {
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }
}
class invoice {

    static public float x_table = 55;
    static public float tablewidth = 475;

    static public float y_address = 682;
    static public float x_salesrep = 455;
    static public float y_invoice = 542;
    static public float imagesize = 90;

    static public float fontsize = 11;
    static public float fontsizesmall = 9;

    static public String fontname = "NotoSerif-Regular";

    static public StringBuilder basefontoptions = new StringBuilder();

    /* -----------------------------------
    * Place company stationery as background
    * -----------------------------------
    */
    static void create_stationery(PDFlib p)
    {
        String sender =
            "Kraxi Systems, Inc. &#x2022; 17, Aviation Road &#x2022; Paperfield";
        String stationeryfontname= "NotoSerif-Regular";

        String stationeryfilename = "kraxi_logo.pdf";

        float y_company_logo = 748;

        String senderfull =
            "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";

        int         page, stationery;
        StringBuilder optlist = new StringBuilder();
        int         tf;

        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());

        /* ---------------------------------e
        * 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);
    }

    /* -----------------------------------
    * Place address and header text
    * -----------------------------------
    */
    static void create_header(PDFlib  p)
    {
        String salesrepfilename = "sales_rep4.jpg";
        String salesrepname = "Lucy Irwin";
        String salesrepcaption = "Local sales rep:";
        String invoiceheader = "INVOICE 2012-03";
        System.DateTime ltime;
        StringBuilder date = new StringBuilder();


        String address =
            "John Q. Doe\n" +
            "255 Customer Lane\n" +
            "Suite B\n" +
            "12345 User Town\n" +
            "Everland";

        string[] months = { "January", "February", "March", "April", 
                            "May", "June", "July", "August", "September", 
                            "October", "November", "December" };


        StringBuilder optlist = new StringBuilder();
        int           salesrepimage;
        int           tf;

        /* -----------------------------------
        * 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;
        date.Length = 0;
        date.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(date.ToString(), x_table + tablewidth, y_invoice, optlist.ToString());
    }

    static void Main(string[] args) {
        PDFlib p = null;
        // This is where font/image/PDF input files live. Adjust as necessary.
        string searchpath = "../../../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.
        //
        string fontpath = "../../../../resource/font";

        string closingtext =
            "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.";

        articledata[] dataset = {
            new articledata( "Super Kite",  20, 2),
            new articledata( "Turbo Flyer", 40, 5),
            new articledata( "Giga Trash", 180, 1),
            new articledata( "Bare Bone Kit", 50, 3),
            new articledata( "Nitty Gritty", 20, 10),
            new articledata( "Pretty Dark Flyer", 75, 1),
            new articledata( "Free Gift", 0, 1),
        };

        string[] headers = {
            "ITEM", "DESCRIPTION", "QUANTITY", "PRICE", "AMOUNT"
        };

        string[] alignments = {
            "right", "left", "right", "right", "right"
        };

        try     
        {
            p = new PDFlib();

            int         i, pagecount=0;
            int         row, col, tbl, tf;
            String      result;
            float       total;
            StringBuilder buf = new StringBuilder();
            StringBuilder optlist = new StringBuilder();

            CultureInfo culture = 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");

            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; col <= headers.Length; col++)
            {
                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());
            }
            row++;

            /* ---------- Data rows: one for each article */
            total = 0;

            for (i = 0; i <  dataset.Length; i++) {
                float sum = 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());

                /* 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());

                /* 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());

                /* 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());

                /* 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());

                total += sum;
                row++;
            }

            /* ---------- 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());


            /* ---------- 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 {
                float top;

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

                if (++pagecount == 1)
                {
                    create_stationery(p);
                    create_header(p);
                    top = y_invoice - 3*fontsize;
                }
                else
                {
                    top = 50;
                }

                /* 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") {
                    throw new Exception("Couldn't place table: "
                        + p.get_errmsg());
                }

                p.end_page_ext("");
            } while (result == "_boxfull");

            p.delete_table(tbl, "");

            p.end_document("");

        }
        catch (PDFlibException e)
        {
            // caught exception thrown by PDFlib
            Console.WriteLine("PDFlib exception occurred in invoice sample:");
            Console.WriteLine("[{0}] {1}: {2}\n", e.get_errnum(),
                    e.get_apiname(), e.get_errmsg());
        } finally {
            if (p != null) {
                p.Dispose();
            }
        }
    }
}
