using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.Windows.Xps;
using System.Printing;
using System.Windows.Xps.Packaging;
using System.IO;
using System.Diagnostics;
using System.Windows.Documents.Serialization;
using System.Windows.Controls.Primitives;


namespace CreateXpsDoc
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class Window1 : System.Windows.Window
    {

        public Window1()
        {
            InitializeComponent();
        }

        public FixedDocument CreateDoc()
        {
            // Example 15-2. Creating a FixedDocumentSequence containing a FixedDocument 

            FixedDocumentSequence fds = new FixedDocumentSequence();
            FixedDocument doc = new FixedDocument();

            DocumentReference docReference = new DocumentReference();
            docReference.SetDocument(doc);

            fds.References.Add(docReference);

            // End of Example 15-2.


            // Example 15-5. Adding FixedPages to a FixedDocument

            FixedPage page1 = new FixedPage();
            PageContent page1Content = new PageContent();
            ((IAddChild) page1Content).AddChild(page1);
            doc.Pages.Add(page1Content);

            FixedPage page2 = new FixedPage();
            PageContent page2Content = new PageContent();
            ((IAddChild) page2Content).AddChild(page2);
            doc.Pages.Add(page2Content);

            // End of Example 15-5.


            // Example 15-7. Adding content to a FixedPage

            Canvas content1 = new Canvas();
            page1.Children.Add(content1);
            TextBlock text1 = new TextBlock();
            text1.Text = "Hello, world!";
            text1.FontFamily = new FontFamily("Palatino Linotype");
            text1.FontSize = 50;
            Canvas.SetLeft(text1, 100);
            Canvas.SetTop(text1, 200);
            content1.Children.Add(text1);

            // End of Example 15-7.


            return doc;
        }

        private void PrintDoc()
        {
            // Example 15-9. Obtaining an XpsDocumentWriter for printing

            PrintDocumentImageableArea imageArea = null;
            XpsDocumentWriter xpdw = PrintQueue.CreateXpsDocumentWriter(ref imageArea);
            if (xpdw != null)
            {
                FixedDocument doc = CreateDoc();
                xpdw.Write(doc);
            }

            // End of Example 15-9.
        }

        private void WriteDoc(string xpsOutputPath)
        {
            // Example 15-10. Obtaining an XpsDocumentWriter for file output

            using (XpsDocument xpsFile = new XpsDocument(xpsOutputPath, FileAccess.Write))
            {
                XpsDocumentWriter xpdw = XpsDocument.CreateXpsDocumentWriter(xpsFile);

                FixedDocument doc = CreateDoc();
                xpdw.Write(doc);
            }

            // End of Example 15-10.
        }

        private void BuildAndPrintFixedDoc()
        {
            // Example 15-11. Printing a FixedDocument

            FixedDocument doc = new FixedDocument();

            // Add first page to document

            FixedPage page1 = new FixedPage();
            PageContent page1Content = new PageContent();
            ((IAddChild) page1Content).AddChild(page1);
            doc.Pages.Add(page1Content);


            // Add content to first page

            Canvas content1 = new Canvas();
            page1.Children.Add(content1);
            TextBlock text1 = new TextBlock();
            text1.Text = "Hello";
            text1.FontSize = 50;
            Canvas.SetLeft(text1, 100);
            Canvas.SetTop(text1, 200);
            content1.Children.Add(text1);


            // Add second page to document

            FixedPage page2 = new FixedPage();
            PageContent page2Content = new PageContent();
            ((IAddChild) page2Content).AddChild(page2);
            doc.Pages.Add(page2Content);


            // Add content to second page

            Canvas content2 = new Canvas();
            page2.Children.Add(content2);
            TextBlock text2 = new TextBlock();
            text2.Text = "World";
            text2.FontSize = 50;
            Canvas.SetLeft(text2, 100);
            Canvas.SetTop(text2, 200);
            content2.Children.Add(text2);


            // Print document

            PrintDocumentImageableArea imageArea = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref imageArea);
            if (xpsdw != null)
            {
                xpsdw.Write(doc);
            }

            // End of Example 15-11.
        }

        private void PrintSingleVisual()
        {
            // Example 15-12. Printing a single Visual

            PrintDocumentImageableArea area = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
            if (xpsdw != null)
            {
                TextBlock myVisual = new TextBlock();

                double leftMargin = area.OriginWidth;
                double topMargin = area.OriginHeight;
                double rightMargin = area.MediaSizeWidth - area.ExtentWidth - leftMargin;
                double bottomMargin = area.MediaSizeHeight - area.ExtentHeight - topMargin;
                myVisual.Margin = new Thickness(leftMargin, topMargin,
                                                rightMargin, bottomMargin);

                myVisual.Text = "Hello, world";

                Size outputSize = new Size(area.MediaSizeWidth, area.MediaSizeHeight);
                myVisual.Measure(outputSize);
                myVisual.Arrange(new Rect(outputSize));
                myVisual.UpdateLayout();

                xpsdw.Write(myVisual);
            }

            // End of Example 15-12.
        }

        private Visual MakeVisualWithMargins(PrintDocumentImageableArea area)
        {
            // Example 15-13. Setting fixed print margins

            TextBlock myVisual = new TextBlock();

            double leftMargin = 96;    // 1 inch
            double topMargin = 144;    // 1.5 inches
            double rightMargin = 96;   // 1 inch
            double bottomMargin = 144; // 1.5 inches

            // making sure that we’re inside the physical
            // limitations of the printer

            Debug.Assert(leftMargin >= area.OriginWidth);
            Debug.Assert(topMargin >= area.OriginHeight);
            Debug.Assert(rightMargin <= area.OriginWidth + area.ExtentWidth);
            Debug.Assert(topMargin <= area.OriginHeight + area.ExtentHeight);

            myVisual.Margin = new Thickness(leftMargin, topMargin,
                                                rightMargin, bottomMargin);

            // End of Example 15-13.

            return myVisual;
        }

        private void PrintMultipleVisuals()
        {
            // Example 15-14. Printing multiple Visuals

            PrintDocumentImageableArea area = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
            if (xpsdw != null)
            {
                SerializerWriterCollator c = xpsdw.CreateVisualsCollator();
                c.BeginBatchWrite();
                for (int i = 1; i <= 10; ++i)
                {
                    TextBlock tb = new TextBlock();
                    tb.Text = i.ToString();
                    tb.TextAlignment = TextAlignment.Center;
                    tb.VerticalAlignment = VerticalAlignment.Center;
                    tb.FontSize = 500;
                    tb.FontFamily = new FontFamily("Verdana");

                    tb.Margin = new Thickness(area.OriginWidth, area.OriginHeight, 0, 0);
                    Size outputSize = new Size(area.ExtentWidth, area.ExtentHeight);
                    tb.Measure(outputSize);
                    tb.Arrange(new Rect(outputSize));
                    tb.UpdateLayout();

                    c.Write(tb);
                }
                c.EndBatchWrite();
            }

            // End of Example 15-14.
        }


        // Example 15-15. Printing with DocumentPaginator

        public static void PrintPaginatedDocument(IDocumentPaginatorSource dps)
        {
            PrintDocumentImageableArea area = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
            if (xpsdw != null)
            {
                xpsdw.Write(dps.DocumentPaginator);
            }
        }

        // End of Example 15-15.


        public static void PrintPaginatedDocumentWithSize(IDocumentPaginatorSource dps)
        {
            // Example 15-16. Setting a DocumentPaginator’s PageSize

            PrintDocumentImageableArea area = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
            if (xpsdw != null)
            {
                DocumentPaginator paginator = dps.DocumentPaginator;
                paginator.PageSize = new Size(area.ExtentWidth, area.ExtentHeight);
                xpsdw.Write(paginator);
            }

            // End of Example 15-16.
        }

        // Example 15-17. Printing a FlowDocument with page numbers

        public static void PrintFlowDocWithPageNumbers(FlowDocument myFlowDoc)
        {
            PrintDocumentImageableArea area = null;
            XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
            if (xpsdw != null)
            {
                IDocumentPaginatorSource dps = myFlowDoc;
                DocumentPaginator sourceFlowDocPaginator = dps.DocumentPaginator;

                const int HeaderFooterHeight = 30;
                sourceFlowDocPaginator.PageSize = new Size(area.ExtentWidth,
                    area.ExtentHeight - 2 * HeaderFooterHeight);

                if (!sourceFlowDocPaginator.IsPageCountValid)
                {
                    sourceFlowDocPaginator.ComputePageCount();
                }

                FixedDocument outputFixedDoc = BuildFixedDocument(myFlowDoc, area,
                    sourceFlowDocPaginator, HeaderFooterHeight);

                xpsdw.Write(outputFixedDoc);
            }
        }

        // End of Example 15-17.


        // Example 15-18. Building a FixedDocument from a FlowDocument

        static FixedDocument BuildFixedDocument(FlowDocument myFlowDoc,
            PrintDocumentImageableArea area, DocumentPaginator sourceFlowDocPaginator,
            int headerFooterHeight)
        {

            FixedDocument outputFixedDoc = new FixedDocument();

            for (int pageNo = 0; pageNo < sourceFlowDocPaginator.PageCount; ++pageNo)
            {
                Canvas pageCanvas = new Canvas();
                pageCanvas.Margin = new Thickness(192);

                AddHeaderAndFooter(myFlowDoc, area, sourceFlowDocPaginator,
                                   headerFooterHeight, pageNo, pageCanvas);
                AddPageBody(sourceFlowDocPaginator,
                            headerFooterHeight, pageNo, pageCanvas);

                AddPageToDocument(area, outputFixedDoc, pageCanvas);

            }
            return outputFixedDoc;
        }

        // End of Example 15-18.


        // Example 15-19. Adding the header and footer

        static void AddHeaderAndFooter(FlowDocument myFlowDoc,
            PrintDocumentImageableArea area,
            DocumentPaginator sourceFlowDocPaginator,
            int headerFooterHeight, int pageNo, Canvas pageCanvas)
        {

            TextBlock header = new TextBlock();
            header.Text = "My Document";
            header.FontSize = 20;
            header.FontWeight = FontWeights.Bold;
            header.TextAlignment = TextAlignment.Center;
            header.Width = sourceFlowDocPaginator.PageSize.Width;
            pageCanvas.Children.Add(header);

            TextBlock footer = new TextBlock();
            footer.Text += "Page " + (pageNo + 1);
            footer.TextAlignment = TextAlignment.Center;
            footer.FontFamily = myFlowDoc.FontFamily;
            footer.Width = sourceFlowDocPaginator.PageSize.Width;
            Canvas.SetTop(footer, area.ExtentHeight - headerFooterHeight);
            pageCanvas.Children.Add(footer);
        }

        // End of Example 15-19.


        // Example 15-20. Adding the page body

        private static void AddPageBody(DocumentPaginator sourceFlowDocPaginator,
                int headerFooterHeight, int pageNo, Canvas pageCanvas)
        {

            DocumentPageView dpv = new DocumentPageView();
            dpv.DocumentPaginator = sourceFlowDocPaginator;
            dpv.PageNumber = pageNo;
            Canvas.SetTop(dpv, headerFooterHeight);
            pageCanvas.Children.Add(dpv);
        }

        // End of Example 15-20.


        // Example 15-21. Adding pages to the FixedDocument

        private static void AddPageToDocument(PrintDocumentImageableArea area,
            FixedDocument outputFixedDoc, Canvas pageCanvas)
        {

            FixedPage fp = new FixedPage();
            fp.Width = area.MediaSizeWidth;
            fp.Height = area.MediaSizeHeight;
            fp.Children.Add(pageCanvas);

            PageContent pc = new PageContent();
            ((IAddChild) pc).AddChild(fp);
            outputFixedDoc.Pages.Add(pc);
        }

        // End of Example 15-21.
    }
}