//
// Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved.
//
using System;
using System.IO;
using System.Windows;
using System.Windows.Documents; 
using System.Windows.Media; 
using System.Xml;
using System.Windows.Controls;
using System.Windows.Markup;

using pdftron;
using pdftron.Common;
using pdftron.SDF;
using pdftron.PDF;
using pdftron.Xaml;

namespace Xaml2PdfTestCS
{
    /// <summary>
    /// This sample shows how use pdftron.Xaml.Convert to convert .xaml files 
    /// into PDF documents with control over headers and footers, main body placement,
    /// and column widths.  Pagination is controlled by specifying the page size and 
    /// body size (margins) and all pages are appended to a PDFDoc which can then be
    /// further manipulated using the PDFNet API.
    /// 
    /// Three types of XAML objects are convertible using pdftron.Xaml.Convert:
    /// - FlowDocument's which describe content that is reflowable from page to page
    /// - FixedDocument's which describe content that has been placed on a fixed page
    /// - Blocks such as Canvas, RichTextBox, Section etc which can be wrapped or inserted 
    ///     directly into a FlowDocument
    ///     
    /// This sample has three example uses of pdftron.Xaml.Convert:
    /// - CreateXamlFlowDocumentFromCanvas() demonstrates how to read in a Canvas
    ///   described in a .xaml file and convert it to PDF.
    /// - CreateXamlTableAndConvert() demonstrates how to programmatically create
    ///   a FlowDocument with a table, and then convert it to PDF as a single column
    ///   document.
    /// - ConvertXamlFlowDocumentsFromFiles() demonstrates how to define functions to
    ///   create page headers and footers.
    ///   
    /// Limitations:
    /// Requires Microsoft .NET 3.5
    /// 
    /// There are many Xaml classes that cannot be added to FlowDocument or FixedDocuments and
    /// therefore this sample converter cannot convert Page, Window or Frame objects.
    /// </summary>
    class Program
    {
        private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
        static Program() {}
        
        // Relative path to the folder containing test files.
        const string inputPath = "../../TestFiles/";
        const string outputPath = "../../../../TestFiles/Output/";
        
        /// <summary>
        /// Entry point for the sample.
        /// </summary>
        /// <param name="args">command line arguments (ignored)</param>
        [STAThread]
        static void Main(string[] args)
        {
            PDFNet.Initialize(PDFTronLicense.Key);
            try
            {
                CreateXamlFlowDocumentFromCanvas();
                CreateXamlTableAndConvert();
                ConvertXamlFlowDocumentsFromFiles();
            }
            catch (PDFNetException e)
            {
                Console.WriteLine(e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            PDFNet.Terminate();
        }

        /// <summary>
        /// Demonstrate how to load a Xaml file containing a Canvas and convert
        /// it to PDF.
        /// </summary>
        static public void CreateXamlFlowDocumentFromCanvas()
        {
            // load the Xaml file containing the canvas
            string rawXamlText = "";
            using(StreamReader streamReader = File.OpenText(inputPath + "xamlshield.xaml"))
            {
                rawXamlText = streamReader.ReadToEnd();
            }
            StringReader stringReader = new StringReader(rawXamlText);
            XmlReader xmlReader = XmlReader.Create(stringReader);
            Canvas canvasImage = (Canvas)XamlReader.Load(xmlReader);

            // Now convert to PDF
            using (PDFDoc pdfdoc = new PDFDoc())
            {
                pdftron.Xaml.Convert.ToPdf(pdfdoc, canvasImage);
                string outputFileName = outputPath + "xamlshield.pdf";
                pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);

                Console.WriteLine("Wrote " + outputFileName);
                Console.WriteLine("Done.");
            }
        }

        /// <summary>
        /// Demonstrate how to create a Xaml table and convert it to 
        /// PDF.  Also demonstrates how to use the ConverterOptions.NumColumns
        /// setting to draw the table across the page, rather than across
        /// the left column of a two column page.
        /// </summary>
        static public void CreateXamlTableAndConvert()
        {
            // from MSDN SDK Sample TableCsharpSample
            FlowDocument flowDoc = new FlowDocument();

            pdftron.Xaml.ConverterOptions options = new ConverterOptions();
            options.NumColumns = 1;

            // Create the Table...
            Table table1 = new Table();
            // ...and add it as a content element of the TextFlow.
            flowDoc.Blocks.Add(table1);
            // tf1.ContentStart.InsertTextElement(table1);

            // Set some global formatting properties for the table.
            table1.CellSpacing = 10;
            table1.Background = Brushes.White;

            // Create 6 columns and add them to the table's Columns collection.
            int numberOfColumns = 6;
            for (int x = 0; x < numberOfColumns; x++) table1.Columns.Add(new TableColumn());

            // Set alternating background colors for the middle colums.
            table1.Columns[1].Background =
                table1.Columns[3].Background =
                Brushes.LightSteelBlue;
            table1.Columns[2].Background =
                table1.Columns[4].Background =
                Brushes.Beige;

            // Create and add an empty TableRowGroup to hold the table's Rows.
            table1.RowGroups.Add(new TableRowGroup());

            // Add the first (title) row.
            table1.RowGroups[0].Rows.Add(new TableRow());

            // Alias the current working row for easy reference.
            TableRow currentRow = table1.RowGroups[0].Rows[0];

            // Global formatting for the title row.
            currentRow.Background = Brushes.Silver;
            currentRow.FontSize = 40;
            currentRow.FontWeight = System.Windows.FontWeights.Bold;

            // Add the header row with content, 
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("2004 Sales Project"))));
            // and set the row to span all 6 columns.
            currentRow.Cells[0].ColumnSpan = 6;

            // Add the second (header) row.
            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[1];

            // Global formatting for the header row.
            currentRow.FontSize = 18;
            currentRow.FontWeight = FontWeights.Bold;

            // Add cells with content to the second row.
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Product"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 1"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 2"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 3"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 4"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("TOTAL"))));

            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[2];

            // Global formatting for the row.
            currentRow.FontSize = 12;
            currentRow.FontWeight = FontWeights.Normal;

            // Add cells with content to the third row.
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Widgets"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$50,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$55,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$60,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$65,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$230,000"))));

            // Bold the first cell.
            currentRow.Cells[0].FontWeight = FontWeights.Bold;

            // Add the fourth row.
            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[3];

            // Global formatting for the row.
            currentRow.FontSize = 12;
            currentRow.FontWeight = FontWeights.Normal;

            // Add cells with content to the third row.
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Wickets"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$100,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$120,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$160,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$200,000"))));
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$580,000"))));

            // Bold the first cell.
            currentRow.Cells[0].FontWeight = FontWeights.Bold;

            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[4];

            // Global formatting for the footer row.
            currentRow.Background = Brushes.LightGray;
            currentRow.FontSize = 18;
            currentRow.FontWeight = System.Windows.FontWeights.Normal;

            // Add the header row with content, 
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Projected 2004 Revenue: $810,000"))));
            // and set the row to span all 6 columns.
            currentRow.Cells[0].ColumnSpan = 6;

            // The PDFDoc to put the converted .xaml document into
            using (PDFDoc pdfdoc = new PDFDoc())
            {
                pdftron.Xaml.Convert.ToPdf(pdfdoc, flowDoc, options );
                string outputFileName = outputPath + "CreateXamlTableAndConvert.pdf";
                pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);

                Console.WriteLine("Wrote " + outputFileName);
                Console.WriteLine("Done.");
            }
        }

        /// <summary>
        /// Demonstrate how to convert Xaml files directly from .xaml to .pdf
        /// </summary>
        static public void ConvertXamlFlowDocumentsFromFiles()
        {
            string[] inputFileNames = new string[] {"BobWatson.xaml",
                                         "chocolate.xaml",
                                         "FlowDocumentFormats.xaml",
                                         "FlowDocumentSample1.xaml",
                                         "FlowDocumentSample2.xaml",
                                         "FlowDocumentSample3.xaml",
                                         "MarkusEgger.xaml",
                                         "MarkusEgger-withImageReference.xaml",
                                         "RichTextBox.xaml",
                                         "ThreeRectangles.xaml",
                                         "WPFNotepad-1.xaml"};

            foreach( string inputFileName in inputFileNames)
            {
                try
                {
                    // The PDFDoc to put the converted .xaml document into
                    using (PDFDoc pdfdoc = new PDFDoc())
                    {

                        ConverterOptions options = new ConverterOptions();
                        options.HeaderFunc = new ConverterOptions.DrawHeaderFooter(MyDrawHeader);
                        options.FooterFunc = new ConverterOptions.DrawHeaderFooter(MyDrawFooter);

                        pdftron.Xaml.Convert.ToPdf(pdfdoc, inputPath + inputFileName, options);
                        
                        // output the PDFDoc:
                        string outputFileName = inputFileName;
                        outputFileName = outputFileName.Remove(outputFileName.LastIndexOf('.')) + ".pdf";
                        outputFileName = outputPath + outputFileName;
                        pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);

                        Console.WriteLine("Wrote " + outputFileName);
                        Console.WriteLine("Done.");
                    }
                }
                catch (PDFNetException e)
                {
                    Console.WriteLine(e.Message);
                    Console.WriteLine("For file " + inputFileName);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    Console.WriteLine("For file " + inputFileName);
                }
            }
        }

        /// <summary>
        /// This variable hold the typeface resource used by the header and footer.
        /// Any resource that you use in the header and footer delegates must persist 
        /// until the document is serialized.
        /// </summary>
        static Typeface typeface = null;

        /// <summary>
        /// Example Header delegate for ConverterOptions, used in ConvertXamlFlowDocumentsFromFiles()
        /// </summary>
        static public void MyDrawHeader(DrawingContext context, pdftron.PDF.Rect bounds,
                                        pdftron.PDF.Rect bodyBounds, Size pageSize, int pageNumber)
        {
            // any resources that you use in the header and footer delegates must persist until the 
            // document is serialized
            if (typeface == null)
            {
                typeface = new Typeface("Comic Sans MS");
            }

            //12 point text for header page number
            FormattedText text = new FormattedText("Page " + (pageNumber + 1),
                System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                typeface, 12, Brushes.Black);
            // the translation applied to the page put the origin at the top left corner of the 
            // body rectangle.  So negative y values move us out of the body into the top margin
            context.DrawText(text, new System.Windows.Point(0, -bounds.y2));
        }

        /// <summary>
        /// Example Footer delegate for ConverterOptions, used in ConvertXamlFlowDocumentsFromFiles()
        /// </summary>
        static public void MyDrawFooter(DrawingContext context, pdftron.PDF.Rect bounds,
                                        pdftron.PDF.Rect bodyBounds, Size pageSize, int pageNumber)
        {
            // any resources that you use in the header and footer delegates must persist until the 
            // document is serialized
            if (typeface == null)
            {
                typeface = new Typeface("Comic Sans MS");
            }

            //8 point text for footer in DarkGreen
            FormattedText text = new FormattedText("This is the footer for page " + (pageNumber + 1),
                System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                typeface, 8, Brushes.DarkGreen);

            // The translation applied to the page puts the origin at the top left corner of the 
            // body rectangle, adjust.
            context.DrawText(text, new System.Windows.Point(0, bounds.y1 - bodyBounds.y1));
        }

    }
}
