/*
 * Starter sample for OpenType font features
 *
 * Demonstrate various typographic OpenType features after checking
 * whether a particular feature is supported in a font.
 *
 * Required data: suitable font with OpenType feature tables
 *
 * This sample uses a default font which includes various features.
 * Depending on the implementation of the features you
 * may have to replace the sample text below.
 */

using System;
using System.Text;
using PDFlib_dotnet;

struct testcase {
    public string description;
    /* the default test font above will be used if this string is empty */
    public string fontname;
    public string feature;
    public string text;
    // Constructor:
    public testcase(string description, string fontname,
        string feature, string text)
    {
        this.description = description;
        this.fontname = fontname;
        this.feature = feature;
        this.text = text;
    }
};

class starter_opentype {
  static int Main(string[] args)
  {

    /* This is where the data files are. Adjust as necessary. */
    string searchpath = "../../../data";
    string outfile = "starter_opentype.pdf";

    StringBuilder optlist = new StringBuilder();;
    PDFlib p = null;
    int row, col, table, test, font;
    double llx= 50, lly=50, urx=800, ury=550;
    string result;

    /* This font will be used unless another one is specified in the table */
    string defaulttestfont = "NotoSerif-Regular";

    string[] header = {
        "OpenType feature",
        "Option list",
        "Font name",
        "Raw input (feature disabled)",
        "Feature enabled",
    };
    int MAXCOL = header.Length;

    testcase[] testcases = {
        new testcase(
          "ligatures",
          "",
          "liga",
           "ff fi fl ffi ffl"
        ),
        new testcase(
          "discretionary ligatures",
          "",
          "dlig",
           "ch tz"
        ),
        new testcase(
          "small capitals",
          "",
          "smcp",
           "PostScript"
        ),
        new testcase(
          "ordinals",
          "",
          "ordn",
           "1o 2a 3o"
        ),
        new testcase(
          "fractions",
          "",
          "frac",
           "1/2 1/4 3/4"
        ),
        new testcase(
          "slashed zero",
          "",
          "zero",
           "0"
        ),
        new testcase(
          "historical forms",
          "",
          "hist",
           "s"
        ),
        new testcase(
          "proportional figures",
          "",
          "pnum",
           "0123456789"
        ),
        new testcase(
          "old-style figures",
          "",
          "onum",
           "0123456789"
        ),
        new testcase(
          "lining figures",
          "",
          "lnum",
           "0123456789"
        ),
        new testcase(
          "superscript",
          "",
          "sups",
           "123"
        ),
        new testcase(
          "subscript",
          "",
          "subs",
           "H2SO4"
        ),
    };
    int n_testcases = testcases.Length;

    try {
        /* create a new PDFlib object */
        p = new PDFlib();

        /* This means that formatting and other errors will raise an
         * exception. This simplifies our sample code, but is not
         * recommended for production code.
         */
        p.set_option("errorpolicy=exception");

        // Set the search path for fonts and PDF files 
        p.set_option("SearchPath={{" + searchpath + "}} charref=true");


        /* Set an output path according to the name of the topic */
        if (p.begin_document(outfile, "") == -1) {
            Console.WriteLine("Error: {0}\n", p.get_errmsg());
            return(2);
        }

        p.set_info("Creator", "PDFlib starter sample");
        p.set_info("Title", "starter_opentype");

        table = -1;

        /* Table header */
        for (row=1, col=1; col <= MAXCOL; col++)
        {
            optlist.Length = 0;
            optlist.Append("fittextline={fontname=NotoSerif-Regular ");
            optlist.Append("fontsize=12} margin=4");
            table = p.add_table_cell(table, col, row, header[col-1],
                optlist.ToString());
        }

        /* Create a table with feature samples, one feature per table row */
        for (row=2, test=0; test < n_testcases; row++, test++)
        {
            string testfont;
            StringBuilder buf = new StringBuilder();;

            /* Use the entry in the test table if available, and the
             * default test font otherwise. This way we can easily check
             * a font for all features, as well as insert suitable fonts
             * for individual features.
             */
            if (testcases[test].fontname != "")
                testfont = testcases[test].fontname;
            else
                testfont = defaulttestfont;

            col=1;

            /* Common option list for columns 1-3 */
            optlist.Length = 0;
            optlist.Append("fittextline={fontname=NotoSerif-Regular ");
            optlist.Append("fontsize=12} margin=4");

            /* Column 1: feature description */
            table = p.add_table_cell(table, col++, row,
                testcases[test].description, optlist.ToString());

            /* Column 2: option list */
            buf.Length = 0;
            buf.Append("features={");
            buf.AppendFormat("{0}", testcases[test].feature);
            buf.Append("}");
            table = p.add_table_cell(table, col++, row, buf.ToString(),
                optlist.ToString());

            /* Column 3: font name */
            table = p.add_table_cell(table, col++, row, testfont, optlist.ToString());

            /* Column 4: raw input text with  feature disabled */
            optlist.Length = 0;
            optlist.Append("fittextline={fontname={");
            optlist.AppendFormat("{0}", testfont);
            optlist.Append("} fontsize=12} margin=4");
            table = p.add_table_cell(table, col++, row,
                    testcases[test].text, optlist.ToString());

            /* Column 5: text with enabled feature, or warning if the
             * feature is not available in the font
             */
            font = p.load_font(testfont, "unicode", "");

            /* Check whether font contains the required feature table */
            optlist.Length = 0;
            optlist.AppendFormat( "name={0}", testcases[test].feature);
            if (p.info_font(font, "feature", optlist.ToString()) == 1)
            {
                /* feature is available: apply it to the text */
                optlist.Length = 0;
                optlist.Append("fittextline={fontname={");
                optlist.AppendFormat("{0}", testfont);
                optlist.Append("} fontsize=12 features={");
                optlist.AppendFormat("{0}", testcases[test].feature);
                optlist.Append("}} margin=4");
                table = p.add_table_cell(table, col++, row,
                           testcases[test].text, optlist.ToString());
            }
            else
            {
                /* feature is not available: emit a warning */
                optlist.Length = 0;
                optlist.Append(
                     "fittextline={fontname=NotoSerif-Regular " +
                     "fontsize=12 fillcolor=red} margin=4");
                table = p.add_table_cell(table, col++, row,
                        "(feature not available in this font)", optlist.ToString());
            }

        }

        /*
         * Loop until all of the table is placed; create new pages
         * as long as more table instances need to be placed.
         */
        do {
            p.begin_page_ext(0, 0, "width=a4.height height=a4.width");

            /* Shade every other row; draw lines for all table cells. */
            optlist.Length = 0;
            optlist.Append( "header=1 fill={{area=rowodd " +
                "fillcolor={gray 0.9}}} stroke={{line=other}} ");

            /* Place the table instance */
            result = p.fit_table(table, llx, lly, urx, ury, optlist.ToString());

            if (result == "_error")
            {
                Console.WriteLine("Couldn't place table: {0}\n", p.get_errmsg());
                return(2);
            }

            p.end_page_ext("");

        } while (result == "_boxfull");

        p.end_document("");
    }

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