/***************************************************************************/
/**                                                                       **/
/**                               MAGICARD                                **/
/**                                                                       **/
/***************************************************************************/
/**                                                                       **/
/**  PROJECT      : SDK C# Demo - Ultima Printers                         **/
/**                                                                       **/
/**  MODULE NAME  : PrintDemo.cs                                          **/
/**                                                                       **/
/**  COPYRIGHT    : Magicard                                              **/
/**                                                                       **/
/***************************************************************************/
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Collections.Generic; 
using System.Windows.Forms;
using System.Runtime.InteropServices;
using SDKShim;

namespace CSharpDemo
{
    public partial class SDK_CSDemo : Form
    {
        #region === Initialisation ===

        private void InitPrintDemoTab()
        {
            InitColorCombos();
            InitShapeCombos();

#if (x86)
            TextFrontBox.Text = "Front - First Line of C# Text (32 bit)";
#else
            TextFrontBox.Text = "Front - First Line of C# Text (64 bit)";
#endif
            TextFrontXUpDown.Value      = 10;
            TextFrontYUpDown.Value      = 50;
            TextFrontSizeUpDown.Value   = 10;
            
            ShapeFrontLUpDown.Value     = 60;
            ShapeFrontTUpDown.Value     = 160;
            ShapeFrontRUpDown.Value     = 320;
            ShapeFrontBUpDown.Value     = 320;
            ShapeFrontWidthUpDown.Value = 5;
            
            LineFrontWidthUpDown.Value  = 8;
            LineFrontStartXUpDown.Value = 10;
            LineFrontStartYUpDown.Value = 10;
            LineFrontEndXUpDown.Value   = 800;
            LineFrontEndYUpDown.Value   = 150;

            ImageFrontXUpDown.Value     = 50;
            ImageFrontYUpDown.Value     = 110;

#if (x86)
            TextBackBox.Text = "Back - First Line of C# Text (32 bit)";
#else
            TextBackBox.Text = "Back - First Line of C# Text (64 bit)";
#endif
            TextBackXUpDown.Value       = 10;
            TextBackYUpDown.Value       = 50;
            TextBackSizeUpDown.Value    = 10;
            
            ShapeBackLUpDown.Value      = 60;
            ShapeBackTUpDown.Value      = 160;
            ShapeBackRUpDown.Value      = 320;
            ShapeBackBUpDown.Value      = 320;
            ShapeBackWidthUpDown.Value  = 5;
            
            LineBackWidthUpDown.Value   = 8;
            LineBackStartXUpDown.Value  = 10;
            LineBackStartYUpDown.Value  = 10;
            LineBackEndXUpDown.Value    = 800;
            LineBackEndYUpDown.Value    = 150;

            ImageBackXUpDown.Value      = 50;
            ImageBackYUpDown.Value      = 110;
        }

        Dictionary<Color, string> colorkp = new Dictionary<Color, string>()
        {
          {Color.Red,     "Red"},     
          {Color.Green,   "Green"},   
          {Color.Blue,    "Blue"},   
          {Color.Cyan,    "Cyan"},    
          {Color.Magenta, "Magenta"}, 
          {Color.Yellow,  "Yellow"},  
          {Color.White,   "White"},   
          {Color.Black,   "Black"},   
        };

        //This key pair is used for the shape fill list Combos and is the same
        // as colorkp but with 'Transparent' added
        Dictionary<Color, string> colorfillkp = new Dictionary<Color, string>();

        private void InitColorCombos()
        {
            TextFrontColourCombo.DataSource = new BindingSource(colorkp, null);
            TextFrontColourCombo.DisplayMember = "Value";

            ShapeFrontOutlineCombo.DataSource = new BindingSource(colorkp, null);
            ShapeFrontOutlineCombo.DisplayMember = "Value";

            LineFrontColourCombo.DataSource = new BindingSource(colorkp, null);
            LineFrontColourCombo.DisplayMember = "Value";

            TextBackColourCombo.DataSource = new BindingSource(colorkp, null);
            TextBackColourCombo.DisplayMember = "Value";

            ShapeBackOutlineCombo.DataSource = new BindingSource(colorkp, null);
            ShapeBackOutlineCombo.DisplayMember = "Value";

            LineBackColourCombo.DataSource = new BindingSource(colorkp, null);
            LineBackColourCombo.DisplayMember = "Value";

            //N.B 'Transparent' is also in shape fill combos
            foreach (var pair in colorkp)
            {
                colorfillkp.Add(pair.Key, pair.Value);
            }
            colorfillkp.Add(Color.Transparent, "Transparent");

            ShapeFrontFillCombo.DataSource = new BindingSource(colorfillkp, null);
            ShapeFrontFillCombo.DisplayMember = "Value";

            ShapeBackFillCombo.DataSource = new BindingSource(colorfillkp, null);
            ShapeBackFillCombo.DisplayMember = "Value";
        }

        Dictionary<SDK.Shape, string> shapekp = new Dictionary<SDK.Shape, string>()
        {
            {SDK.Shape.Rectangle, "Rectangle"}, 
            {SDK.Shape.Ellipse,   "Ellipse"  },
            {SDK.Shape.RoundRect, "RoundRect"},
            {SDK.Shape.Pie,       "Pie"      },
            {SDK.Shape.Chord,     "Chord"    }, 
        };

        private void InitShapeCombos()
        {
            ShapeFrontCombo.DataSource    = new BindingSource(shapekp, null);
            ShapeFrontCombo.DisplayMember = "Value";

            ShapeBackCombo.DataSource    = new BindingSource(shapekp, null);
            ShapeBackCombo.DisplayMember = "Value";
        }

        #endregion === Initialisation ===

        //----------------------------------------------------------------------

        #region === Local Methods ===

        private void CardFront_CheckedChanged(object sender, EventArgs e)
        {
            bool control = CardFront.Checked;

            TextFrontEnabled.Enabled       = control;
            ShapeFrontEnabled.Enabled      = control;
            LineFrontEnabled.Enabled       = control;
            ImageFrontEnabled.Enabled      = control;
            MagDataEnabled.Enabled         = control;

            TextFrontBox.Enabled           = control;
            TextFrontColourCombo.Enabled   = control;
            TextFrontSizeUpDown.Enabled    = control;
            TextFrontBold.Enabled          = control;
            TextFrontItalic.Enabled        = control;
            TextFrontUnderline.Enabled     = control;
            TextFrontStrikethrough.Enabled = control;
            TextFrontXUpDown.Enabled       = control;
            TextFrontYUpDown.Enabled       = control;
            TextFrontResin.Enabled         = control;

            ShapeFrontCombo.Enabled        = control;
            ShapeFrontOutlineCombo.Enabled = control;
            ShapeFrontWidthUpDown.Enabled  = control;
            ShapeFrontFillCombo.Enabled    = control;
            ShapeFrontLUpDown.Enabled      = control;
            ShapeFrontTUpDown.Enabled      = control;
            ShapeFrontRUpDown.Enabled      = control;
            ShapeFrontBUpDown.Enabled      = control;
            ShapeFrontResin.Enabled        = control;

            LineFrontColourCombo.Enabled   = control;
            LineFrontWidthUpDown.Enabled   = control;
            LineFrontStartXUpDown.Enabled  = control;
            LineFrontStartYUpDown.Enabled  = control;
            LineFrontEndXUpDown.Enabled    = control;
            LineFrontEndYUpDown.Enabled    = control;
            LineFrontResin.Enabled         = control;

            ImageFrontFileBox.Enabled      = control;
            ImageFrontXUpDown.Enabled      = control;
            ImageFrontYUpDown.Enabled      = control;
            ImageFrontP1UpDown.Enabled     = control;
            ImageFrontP2UpDown.Enabled     = control;
            ImageFrontResin.Enabled        = control;

            Track1MagData.Enabled          = control;
            Track2MagData.Enabled          = control;
            Track3MagData.Enabled          = control;

            PrintButton.Enabled = (control || CardBack.Checked);
        }

        private void CardBackCheck_CheckedChanged(object sender, EventArgs e)
        {
            bool control = CardBack.Checked;

            TextBackEnabled.Enabled       = control;
            ShapeBackEnabled.Enabled      = control;
            LineBackEnabled.Enabled       = control;
            ImageBackEnabled.Enabled      = control;

            TextBackBox.Enabled           = control;
            TextBackColourCombo.Enabled   = control;
            TextBackSizeUpDown.Enabled    = control;
            TextBackBold.Enabled          = control;
            TextBackItalic.Enabled        = control;
            TextBackUnderline.Enabled     = control;
            TextBackStrikethrough.Enabled = control;
            TextBackXUpDown.Enabled       = control;
            TextBackYUpDown.Enabled       = control;
            TextBackResin.Enabled         = control;

            ShapeBackCombo.Enabled        = control;
            ShapeBackOutlineCombo.Enabled = control;
            ShapeBackWidthUpDown.Enabled  = control;
            ShapeBackFillCombo.Enabled    = control;
            ShapeBackLUpDown.Enabled      = control;
            ShapeBackTUpDown.Enabled      = control;
            ShapeBackRUpDown.Enabled      = control;
            ShapeBackBUpDown.Enabled      = control;
            ShapeBackResin.Enabled        = control;

            LineBackColourCombo.Enabled   = control;
            LineBackWidthUpDown.Enabled   = control;
            LineBackStartXUpDown.Enabled  = control;
            LineBackStartYUpDown.Enabled  = control;
            LineBackEndXUpDown.Enabled    = control;
            LineBackEndYUpDown.Enabled    = control;
            LineBackResin.Enabled         = control;

            ImageBackFileBox.Enabled      = control;
            ImageBackXUpDown.Enabled      = control;
            ImageBackYUpDown.Enabled      = control;
            ImageBackP1UpDown.Enabled     = control;
            ImageBackP2UpDown.Enabled     = control;
            ImageBackResin.Enabled        = control;

            PrintButton.Enabled = (control || CardFront.Checked);
        }

        private void nativePrint_CheckedChanged(object sender, EventArgs e)
        {
            bool visible = !nativePrint.Checked;

            TextFrontResin.Visible  = visible;
            ShapeFrontResin.Visible = visible;
            LineFrontResin.Visible  = visible;
            ImageFrontResin.Visible = visible;
            TextBackResin.Visible   = visible;
            ShapeBackResin.Visible  = visible;
            LineBackResin.Visible   = visible;
            ImageBackResin.Visible  = visible;
        }

        #endregion === Local Methods ===

        //----------------------------------------------------------------------

        #region === Front Image Filename ===

        private static string ImageFrontFilename;

        private void ImageFrontButton_Click(object sender, EventArgs e)
        {
            // Displays an OpenFileDialog so the user can select an image file
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = "Image Files (*.bmp;*.jpg;*.png;*.tif)|*.bmp; *.jpg; *.png; *.tif";
            openFileDialog1.Title = "Select an Image File";

            // Show the dialog and get result.
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                ImageFrontFilename = openFileDialog1.FileName;
                ImageFrontFileBox.Text = ImageFrontFilename;
            }
        }

        #endregion === Front Image Filename ===

        //----------------------------------------------------------------------

        #region === Back Image Filename ===

        private static string ImageBackFilename;

        private void ImageBackButton_Click(object sender, EventArgs e)
        {
            // Displays an OpenFileDialog so the user can select an image file
            OpenFileDialog openFileDialog2 = new OpenFileDialog();
            openFileDialog2.Filter = "Image Files (*.bmp;*.jpg;*.png;*.tif)|*.bmp; *.jpg; *.png; *.tif";
            openFileDialog2.Title = "Select an Image File";

            // Show the dialog and get result.
            DialogResult result = openFileDialog2.ShowDialog();
            if (result == DialogResult.OK)
            {
                ImageBackFilename = openFileDialog2.FileName;
                ImageBackFileBox.Text = ImageBackFilename;
            }
        }

        #endregion === Back Image Filename ===

        //----------------------------------------------------------------------

        #region === Print Using Native Functions, Not SDK ===

        void NativePrintText
        (
	        Color   col,
	        decimal size,
	        bool    bold,
	        bool    italic,
	        bool    underline,
	        bool    strikeout,
            decimal textX,
            decimal textY,
	        string  text
        )
        {
            //Define the font
            FontStyle res = FontStyle.Regular;
            if (TextFrontBold.Checked) res |= FontStyle.Bold;
            if (TextFrontItalic.Checked) res |= FontStyle.Italic;
            if (TextFrontUnderline.Checked) res |= FontStyle.Underline;
            if (TextFrontStrikethrough.Checked) res |= FontStyle.Strikeout;

            Font printFont = new Font("Comic Sans MS", decimal.ToInt32(size), res);
            var brush = new SolidBrush(col);
            g.DrawString(text + " (using GDI)",
                         printFont,
                         brush,
                         decimal.ToInt32(textX),
                         decimal.ToInt32(textY));
            printFont.Dispose();
            brush.Dispose();
        }

        void NativePrintShape
        (
            SDK.Shape shape,
            Color     outlinecolour,
            decimal   penwidth,
            Color     fillcolour,
            decimal   left,
            decimal   top,
            decimal   right,
            decimal   bottom
        )
        {
            var pen = new Pen(outlinecolour, decimal.ToInt32(penwidth));

            Rectangle r = new Rectangle(decimal.ToInt32(left),
                                        decimal.ToInt32(top),
                                        decimal.ToInt32(right - left),
                                        decimal.ToInt32(bottom - top));

            switch (shape)
            {
                case SDK.Shape.Ellipse: g.DrawEllipse(pen, r); break;
                case SDK.Shape.Pie: g.DrawPie(pen, r, 45, 60); break;
                case SDK.Shape.Chord: g.DrawArc(pen, r, 45, 60); break;

                case SDK.Shape.RoundRect: //For demo purposes, rounded rectangles are drawn as normal rectangles
                case SDK.Shape.Rectangle:
                    if (fillcolour != Color.Transparent)
                    {
                        //For demo purposes, only doing filled rectangles 
                        var brush = new SolidBrush(fillcolour);
                        g.FillRectangle(brush, r);
                        brush.Dispose();
                    }
                    else
                    {
                        g.DrawRectangle(pen, r);
                    }
                    break;
            }

            pen.Dispose();
        }

        void NativePrintLine
        (
            Color   colour,
            decimal width,
            decimal startX,
            decimal startY,
            decimal endX,
            decimal endY
        )
        {
            var pen = new Pen(colour, decimal.ToInt32(width));
            g.DrawLine(pen,
                       decimal.ToInt32(startX),
                       decimal.ToInt32(startY),
                       decimal.ToInt32(endX),
                       decimal.ToInt32(endY));
            pen.Dispose();
        }

        void NativePrintImage
        (
            string  filename,
            decimal x,
            decimal y,
            decimal p1,
            decimal p2
        )
        {
            Image image  = Image.FromFile(filename);
            
            decimal width  = image.Width;
            decimal height = image.Height;
            if (p1 == 0)
            {
                //No scaling or constraining - Use original size of image
            }
            else if (p2 == 0)
            {
                //Scaling - Modify image dimensions by scaling with the given percentage
                //(p1), while maintaining the aspect ratio
                width  = (width * p1) / 100;
                height = (height * p1) / 100;
            }
            else
            {
                //Constraining - Restrict the image to the given rectangle, ignoring aspect ratio
                //(p1 = new width, p2 = new height)
                width = p1;
                height = p2;
            }

            g.DrawImage(image, new Rectangle(decimal.ToInt32(x), 
                                             decimal.ToInt32(y), 
                                             decimal.ToInt32(width), 
                                             decimal.ToInt32(height)));
            image.Dispose();
        }

        void PrintCard_Front(Graphics g)
        {
            if (TextFrontEnabled.Checked)
            {
                NativePrintText(((KeyValuePair<Color, string>)TextFrontColourCombo.SelectedItem).Key,
	                            TextFrontSizeUpDown.Value,
                                TextFrontBold.Checked,
                                TextFrontItalic.Checked,
                                TextFrontUnderline.Checked,
                                TextFrontStrikethrough.Checked,
                                TextFrontXUpDown.Value,
                                TextFrontYUpDown.Value,
                                TextFrontBox.Text);
            }

            if (ShapeFrontEnabled.Checked)
            {
                NativePrintShape(((KeyValuePair<SDK.Shape, string>)ShapeFrontCombo.SelectedItem).Key,
                                 ((KeyValuePair<Color, string>)ShapeFrontOutlineCombo.SelectedItem).Key,
                                 ShapeFrontWidthUpDown.Value,
                                 ((KeyValuePair<Color, string>)ShapeFrontFillCombo.SelectedItem).Key,
                                 ShapeFrontLUpDown.Value,
                                 ShapeFrontTUpDown.Value,
                                 ShapeFrontRUpDown.Value,
                                 ShapeFrontBUpDown.Value);
            }

            if (LineFrontEnabled.Checked)
            {
                NativePrintLine(((KeyValuePair<Color, string>)LineFrontColourCombo.SelectedItem).Key,
                                LineFrontWidthUpDown.Value,
                                LineFrontStartXUpDown.Value,
                                LineFrontStartYUpDown.Value,
                                LineFrontEndXUpDown.Value,
                                LineFrontEndYUpDown.Value);
            }

            //Has an image file been selected?
            if ((ImageFrontEnabled.Checked)
            && (ImageFrontFileBox.TextLength != 0))
            {
                NativePrintImage(ImageFrontFileBox.Text,
                                 ImageFrontXUpDown.Value,
                                 ImageFrontYUpDown.Value,
                                 ImageFrontP1UpDown.Value,
                                 ImageFrontP2UpDown.Value);
            }
        }

        void PrintCard_Back(Graphics g)
        {
            if (TextBackEnabled.Checked)
            {
                NativePrintText(((KeyValuePair<Color, string>)TextBackColourCombo.SelectedItem).Key,
                                TextBackSizeUpDown.Value,
                                TextBackBold.Checked,
                                TextBackItalic.Checked,
                                TextBackUnderline.Checked,
                                TextBackStrikethrough.Checked,
                                TextBackXUpDown.Value,
                                TextBackYUpDown.Value,
                                TextBackBox.Text);
            }

            if (ShapeBackEnabled.Checked)
            {
                NativePrintShape(((KeyValuePair<SDK.Shape, string>)ShapeBackCombo.SelectedItem).Key,
                                 ((KeyValuePair<Color, string>)ShapeBackOutlineCombo.SelectedItem).Key,
                                 ShapeBackWidthUpDown.Value,
                                 ((KeyValuePair<Color, string>)ShapeBackFillCombo.SelectedItem).Key,
                                 ShapeBackLUpDown.Value,
                                 ShapeBackTUpDown.Value,
                                 ShapeBackRUpDown.Value,
                                 ShapeBackBUpDown.Value);
            }

            if (LineBackEnabled.Checked)
            {
                NativePrintLine(((KeyValuePair<Color, string>)LineBackColourCombo.SelectedItem).Key,
                                LineBackWidthUpDown.Value,
                                LineBackStartXUpDown.Value,
                                LineBackStartYUpDown.Value,
                                LineBackEndXUpDown.Value,
                                LineBackEndYUpDown.Value);
            }

            if ((ImageBackEnabled.Checked)
            && (ImageBackFileBox.TextLength != 0))
            {
                NativePrintImage(ImageBackFileBox.Text,
                                 ImageBackXUpDown.Value,
                                 ImageBackYUpDown.Value,
                                 ImageBackP1UpDown.Value,
                                 ImageBackP2UpDown.Value);
            }
        }

        private int pageNum = 0;

        void printCard_PrintPage(object sender, PrintPageEventArgs e)
        {
            e.Graphics.PageUnit = GraphicsUnit.Pixel;

            switch (pageNum)
            {
            case 0: //Card Front
                if (CardFront.Checked)
                {
                    PrintCard_Front(e.Graphics);
                    if (CardBack.Checked)
                    {
                        e.HasMorePages = true;
                        pageNum = 1;
                    }
                }
                else
                {
                    PrintCard_Back(e.Graphics);
                }
                break;

            case 1: //Card Back
                if (CardBack.Checked)
                {
                    PrintCard_Back(e.Graphics);
                }
                break;
            }
        }

        private void PrintUsingNative()
        {
            Cursor.Current = Cursors.WaitCursor;

            PrintDocument printCard   = new PrintDocument();
            printCard.DocumentName    = "Print Card";
            printCard.PrinterSettings = ps;
            printCard.PrintPage      += printCard_PrintPage;
            pageNum = 0;

            //Update the DevMode
            SDK.Return SDKReturn = SDK.ID_UpdateDevmode(hSession, ref printCard);
            if (SDKReturn != SDK.Return.Success)
            {
                HandleError("UpdateDevMode", SDKReturn);
                return;
            }

            printCard.Print();
 
            Cursor.Current = Cursors.Default;
        }

        #endregion === Print Using Native Functions, Not SDK ===

        //----------------------------------------------------------------------

        #region === Print Button ===

        private void PrintButton_Click(object sender, EventArgs e)
        {
            if (nativePrint.Checked)
            {
                PrintUsingNative();
                return;
            }

            IntPtr FrontDC      = IntPtr.Zero;
            IntPtr BackDC       = IntPtr.Zero;
            IntPtr FrontResinDC = IntPtr.Zero;
            IntPtr BackResinDC  = IntPtr.Zero;

            SDK.Return SDKReturn;

            Cursor.Current = Cursors.WaitCursor;

            SDK.TextDef  TextDefn  = new SDK.TextDef();
            SDK.ShapeDef ShapeDefn = new SDK.ShapeDef();
            SDK.LineDef  LineDefn  = new SDK.LineDef();
            SDK.ImageDef ImageDefn = new SDK.ImageDef();

            do
            {
                //This single pass do..while loop allows us to exit using 'break' (instead of return) and 
                //still reset the cursor at the end :-)

/*
                ************************************************************************************	
                * Currently, the demo app uses the driver settings as configured under the Driver1 *
                * and Driver2 tabs.  Should the developer wish to control this dependent on the    *
                * print selections, and modify these with code, a process such as shown here in    *
                * could be used.                                                                   *
                ************************************************************************************	
                SDK.PrintSetting PrintSettings    = new SDK.PrintSetting();
                SDK.PrintSetting OldPrintSettings = new SDK.PrintSetting();
                
                //Call SDK function to read the print settings for the card so that they can be saved
                SDKReturn = SDK.ID_PrintSettings(hSession, SDK.Action.Read, OldPrintSettings);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("OldPrintSettings", SDKReturn);
                    break;
                }
                PrintSettings = OldPrintSettings;

                //Determine which sides of the card need to be printed
                if (CardFront.Checked && CardBack.Checked)
                {
                    PrintSettings.Duplex = SDK.Duplex.Both;
                }
                else if (CardFront.Checked)
                {
                    PrintSettings.Duplex = SDK.Duplex.FrontOnly;
                }
                else
                {
                    PrintSettings.Duplex = SDK.Duplex.BackOnly;
                }

                //Change the print settings for the card
                SDKReturn = SDK.ID_PrintSettings(hSession, SDK.Action.Write, PrintSettings);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("WritePrintSettings", SDKReturn);
                    break;
                }
*/
                
                //Is there a front to be printed?
                if (CardFront.Checked)
                {
                    //Initialise Front Canvas
                    SDKReturn = SDK.ID_CanvasInit(hSession, out FrontDC, SDK.Canvas.Front);
                    if (SDKReturn != SDK.Return.Success)
                    {
                        HandleError("CanvasInitFront", SDKReturn);
                        break;
                    }

                    if (TextFrontResin.Checked
                    ||  ShapeFrontResin.Checked
                    ||  LineFrontResin.Checked
                    ||  ImageFrontResin.Checked)
                    {
                        SDKReturn = SDK.ID_CanvasInit(hSession, out FrontResinDC, SDK.Canvas.FrontResin);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("CanvasInitFrontResin", SDKReturn);
                            break;
                        }
                    }

                    if (TextFrontEnabled.Checked)
                    {
                        //Front Text....
                        //Define the font
                        TextDefn.FontName   = "Comic Sans MS";
                        TextDefn.FontSize   = decimal.ToInt32(TextFrontSizeUpDown.Value);
                        TextDefn.FontColour = ((KeyValuePair<Color, string>)TextFrontColourCombo.SelectedItem).Key;
                        TextDefn.FontStyle  = 0;
                        if (TextFrontBold.Checked)          TextDefn.FontStyle |= SDK.FontStyle.Bold;
                        if (TextFrontItalic.Checked)        TextDefn.FontStyle |= SDK.FontStyle.Italic;
                        if (TextFrontUnderline.Checked)     TextDefn.FontStyle |= SDK.FontStyle.Underline;
                        if (TextFrontStrikethrough.Checked) TextDefn.FontStyle |= SDK.FontStyle.Strikeout;

                        //Get the location and angle for the text
                        TextDefn.X = decimal.ToInt32(TextFrontXUpDown.Value);
                        TextDefn.Y = decimal.ToInt32(TextFrontYUpDown.Value);
                        TextDefn.Angle = 0;

                        //Get the text to be drawn
                        TextDefn.Text = TextFrontBox.Text;

                        //Call the SDK function to draw the text on the canvas
                        SDKReturn = SDK.ID_DrawText(hSession,
                                                    TextFrontResin.Checked ? SDK.Canvas.FrontResin : SDK.Canvas.Front,
                                                    TextDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawTextFront", SDKReturn);
                            break;
                        }
                    }

                    if (ShapeFrontEnabled.Checked)
                    {
                        //Front Shape...
                        //Get the shape's definition
                        ShapeDefn.Shape      = ((KeyValuePair<SDK.Shape, string>)ShapeFrontCombo.SelectedItem).Key;
                        ShapeDefn.PenColour  = ((KeyValuePair<Color, string>)ShapeFrontOutlineCombo.SelectedItem).Key;
                        ShapeDefn.FillColour = ((KeyValuePair<Color, string>)ShapeFrontFillCombo.SelectedItem).Key;
                        ShapeDefn.PenWidth   = decimal.ToInt32(ShapeFrontWidthUpDown.Value);

                        //Get the shape location
                        ShapeDefn.Area = new Rectangle(decimal.ToInt32(ShapeFrontLUpDown.Value),
                                                       decimal.ToInt32(ShapeFrontTUpDown.Value),
                                                       decimal.ToInt32(ShapeFrontRUpDown.Value) - decimal.ToInt32(ShapeFrontLUpDown.Value),
                                                       decimal.ToInt32(ShapeFrontBUpDown.Value) - decimal.ToInt32(ShapeFrontTUpDown.Value));

                        //Set up the specific parameters for given shapes.
                        //For simplicity, these have been hard codes here rather than GUI selectable
                        switch (ShapeDefn.Shape)
                        {
                        case SDK.Shape.RoundRect:
                            ShapeDefn.P1 = 50;		// Corner Width
                            ShapeDefn.P2 = 50;		// Corner Height
                            break;
                        case SDK.Shape.Pie:
                        case SDK.Shape.Chord:
                            ShapeDefn.P1 = 0;		// Radial 1 X Co-ord
                            ShapeDefn.P2 = 0;		// Radial 1 Y Co-ord
                            ShapeDefn.P3 = 700;	    // Radial 2 X Co-ord
                            ShapeDefn.P4 = 115;	    // Radial 2 Y Co-ord
                            break;
                        }

                        //Call the SDK function to draw the shape on the canvas
                        SDKReturn = SDK.ID_DrawShape(hSession,
                                                     ShapeFrontResin.Checked ? SDK.Canvas.FrontResin : SDK.Canvas.Front,
                                                     ShapeDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawShapeFront", SDKReturn);
                            break;
                        }
                    }

                    if (LineFrontEnabled.Checked)
                    {
                        //Front Line...
                        //Get the line's definition
                        LineDefn.Colour = ((KeyValuePair<Color, string>)LineFrontColourCombo.SelectedItem).Key;
                        LineDefn.Width  = decimal.ToInt32(LineFrontWidthUpDown.Value);

                        //Get the line location
                        LineDefn.StartX = decimal.ToInt32(LineFrontStartXUpDown.Value);
                        LineDefn.StartY = decimal.ToInt32(LineFrontStartYUpDown.Value);
                        LineDefn.EndX   = decimal.ToInt32(LineFrontEndXUpDown.Value);
                        LineDefn.EndY   = decimal.ToInt32(LineFrontEndYUpDown.Value);

                        //Call the SDK function to draw the line on the canvas
                        SDKReturn = SDK.ID_DrawLine(hSession,
                                                    LineFrontResin.Checked ? SDK.Canvas.FrontResin : SDK.Canvas.Front,
                                                    LineDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawLineFront", SDKReturn);
                            break;
                        }
                    }

                    //Has an image file been selected?
                    if ((ImageFrontEnabled.Checked)
                    &&  (ImageFrontFileBox.TextLength != 0))
                    {
                        //Get the image boundaries
                        ImageDefn.X  = decimal.ToInt32(ImageFrontXUpDown.Value);
                        ImageDefn.Y  = decimal.ToInt32(ImageFrontYUpDown.Value);
                        ImageDefn.P1 = decimal.ToInt32(ImageFrontP1UpDown.Value);
                        ImageDefn.P2 = decimal.ToInt32(ImageFrontP2UpDown.Value);

                        ImageDefn.Filename = ImageFrontFileBox.Text;

                        //Call the SDK function to draw the image on the canvas
                        SDKReturn = SDK.ID_DrawImage(hSession,
                                                     ImageFrontResin.Checked ? SDK.Canvas.FrontResin : SDK.Canvas.Front,
                                                     ImageDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawImageFront", SDKReturn);
                            break;
                        }
                    }

                    if (MagDataEnabled.Checked)
                    {
                        //===== Front Magnetic Data =====
                        SDK.MagText magText = new SDK.MagText();

                        if (Track1MagData.TextLength != 0)
                        {
                            magText.Track = 1;
                            magText.Data = Track1MagData.Text;

                            //Call the SDK function to draw the image on the canvas
                            SDKReturn = SDK.ID_DrawMagText(hSession, SDK.Side.Front, magText);
                            if (SDKReturn != SDK.Return.Success)
                            {
                                HandleError("Mag1DataFront", SDKReturn);
                                return;
                            }
                        }

                        if (Track2MagData.TextLength != 0)
                        {
                            magText.Track = 2;
                            magText.Data = Track2MagData.Text;

                            //Call the SDK function to draw the image on the canvas
                            SDKReturn = SDK.ID_DrawMagText(hSession, SDK.Side.Front, magText);
                            if (SDKReturn != SDK.Return.Success)
                            {
                                HandleError("Mag2DataFront", SDKReturn);
                                return;
                            }
                        }

                        if (Track3MagData.TextLength != 0)
                        {
                            magText.Track = 3;
                            magText.Data = Track3MagData.Text;

                            //Call the SDK function to draw the image on the canvas
                            SDKReturn = SDK.ID_DrawMagText(hSession, SDK.Side.Front, magText);
                            if (SDKReturn != SDK.Return.Success)
                            {
                                HandleError("Mag3DataFront", SDKReturn);
                                return;
                            }
                        }
                    }
                }

                //-------------------------------------------------------------------

                //Is there a back to be printed?
                if (CardBack.Checked)
                {
                    /*
                    ***********************************************************************************	
                    * Similarly, settings for the back of the card are defined under the Driver1 and  *
                    * Driver 2 tabs.  This code block reads the settings to save them for restore     *
                    * later, and modifies the colour settings according to the Print Demo tab         *
                    * selections.                                                                     *
                    ***********************************************************************************	
                    SDK.CardSetting BackSettings = new SDK.CardSetting();
                    SDK.CardSetting OldBackSettings = new SDK.CardSetting();

                    //Read the current settings for the Back of the card
                    SDKReturn = SDK.ID_CardSettings(hSession, SDK.Action.Read, SDK.Side.Back, OldBackSettings);
                    if (SDKReturn != SDK.Return.Success)
                    {
                        HandleError("OldCardSettings", SDKReturn);
                        break;
                    }
                    BackSettings = OldBackSettings;

 
                    //If colour is required, modify the card settings for the back of the card
                    if ((((KeyValuePair<Color, string>)TextBackColourCombo.SelectedItem).Key   != Color.Black)
                    ||  (((KeyValuePair<Color, string>)ShapeBackOutlineCombo.SelectedItem).Key != Color.Black)
                    ||  ((((KeyValuePair<Color, string>)ShapeBackFillCombo.SelectedItem).Key    != Color.Black)
                        && (((KeyValuePair<Color, string>)ShapeBackFillCombo.SelectedItem).Key  != Color.Transparent))
                    ||  (((KeyValuePair<Color, string>)LineBackColourCombo.SelectedItem).Key   != Color.Black))
                    {
                        BackSettings.ColourFormat = SDK.ColourFormat.YMCK;

                        SDKReturn = SDK.ID_CardSettings(hSession, SDK.Action.Write, SDK.Side.Back, BackSettings);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("CardSettingsBack", SDKReturn);
                            break;
                        }
                    }
                    */
                    //Initialise Rear Canvas
                    SDKReturn = SDK.ID_CanvasInit(hSession, out BackDC, SDK.Canvas.Back);
                    if (SDKReturn != SDK.Return.Success)
                    {
                        HandleError("CanvasInitBack", SDKReturn);
                        break;
                    }

                    if (TextBackResin.Checked
                    ||  ShapeBackResin.Checked
                    ||  LineBackResin.Checked
                    ||  ImageBackResin.Checked)
                    {
                        SDKReturn = SDK.ID_CanvasInit(hSession, out BackResinDC, SDK.Canvas.BackResin);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("CanvasInitBackResin", SDKReturn);
                            break;
                        }
                    }

                    if (TextBackEnabled.Checked)
                    {
                        //Rear Text
                        TextDefn.FontName   = "Comic Sans MS";
                        TextDefn.FontSize   = decimal.ToInt32(TextBackSizeUpDown.Value);
                        TextDefn.FontColour = ((KeyValuePair<Color, string>)TextBackColourCombo.SelectedItem).Key;
                        TextDefn.FontStyle  = 0;
                        if (TextBackBold.Checked)          TextDefn.FontStyle |= SDK.FontStyle.Bold;
                        if (TextBackItalic.Checked)        TextDefn.FontStyle |= SDK.FontStyle.Italic;
                        if (TextBackUnderline.Checked)     TextDefn.FontStyle |= SDK.FontStyle.Underline;
                        if (TextBackStrikethrough.Checked) TextDefn.FontStyle |= SDK.FontStyle.Strikeout;
                        TextDefn.X = decimal.ToInt32(TextBackXUpDown.Value);
                        TextDefn.Y = decimal.ToInt32(TextBackYUpDown.Value);
                        TextDefn.Angle = 0;

                        TextDefn.Text = TextBackBox.Text;

                        SDKReturn = SDK.ID_DrawText(hSession,
                                                    TextBackResin.Checked ? SDK.Canvas.BackResin : SDK.Canvas.Back,
                                                    TextDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawTextback", SDKReturn);
                            break;
                        }
                    }

                    if (ShapeBackEnabled.Checked)
                    {
                        //Rear Shape
                        ShapeDefn.Shape      = ((KeyValuePair<SDK.Shape, string>)ShapeBackCombo.SelectedItem).Key;
                        ShapeDefn.PenColour  = ((KeyValuePair<Color, string>)ShapeBackOutlineCombo.SelectedItem).Key;
                        ShapeDefn.FillColour = ((KeyValuePair<Color, string>)ShapeBackFillCombo.SelectedItem).Key;

                        ShapeDefn.PenWidth = decimal.ToInt32(ShapeBackWidthUpDown.Value);
                        ShapeDefn.Area = new Rectangle(decimal.ToInt32(ShapeBackLUpDown.Value),
                                                       decimal.ToInt32(ShapeBackTUpDown.Value),
                                                       decimal.ToInt32(ShapeBackRUpDown.Value) - decimal.ToInt32(ShapeBackLUpDown.Value),
                                                       decimal.ToInt32(ShapeBackBUpDown.Value) - decimal.ToInt32(ShapeBackTUpDown.Value));

                        switch (ShapeDefn.Shape)
                        {
                            case SDK.Shape.RoundRect:
                                ShapeDefn.P1 = 50;		// Corner Width
                                ShapeDefn.P2 = 50;		// Corner Height
                                break;
                            case SDK.Shape.Pie:
                            case SDK.Shape.Chord:
                                ShapeDefn.P1 = 0;		// Radial 1 X Co-ord
                                ShapeDefn.P2 = 0;		// Radial 1 Y Co-ord
                                ShapeDefn.P3 = 700;	    // Radial 2 X Co-ord
                                ShapeDefn.P4 = 115;	    // Radial 2 Y Co-ord
                                break;
                        }

                        SDKReturn = SDK.ID_DrawShape(hSession,
                                                     ShapeBackResin.Checked ? SDK.Canvas.BackResin : SDK.Canvas.Back,
                                                     ShapeDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawShapeBack", SDKReturn);
                            break;
                        }
                    }

                    if (LineBackEnabled.Checked)
                    {
                        //Rear Line...
                        //Get the line's definition
                        LineDefn.Colour = ((KeyValuePair<Color, string>)LineBackColourCombo.SelectedItem).Key;
                        LineDefn.Width  = decimal.ToInt32(LineBackWidthUpDown.Value);

                        //Get the line location
                        LineDefn.StartX = decimal.ToInt32(LineBackStartXUpDown.Value);
                        LineDefn.StartY = decimal.ToInt32(LineBackStartYUpDown.Value);
                        LineDefn.EndX   = decimal.ToInt32(LineBackEndXUpDown.Value);
                        LineDefn.EndY   = decimal.ToInt32(LineBackEndYUpDown.Value);

                        //Call the SDK function to draw the line on the canvas
                        SDKReturn = SDK.ID_DrawLine(hSession,
                                                    LineBackResin.Checked ? SDK.Canvas.BackResin : SDK.Canvas.Back,
                                                    LineDefn);
                        if (SDKReturn != SDK.Return.Success)
                        {
                            HandleError("DrawLineBack", SDKReturn);
                            break;
                        }
                    }

                    if (ImageBackEnabled.Checked)
                    {
                        //Has an image file been selected?
                        if (ImageBackFileBox.TextLength != 0)
                        {
                            //Get the image boundaries
                            ImageDefn.X  = decimal.ToInt32(ImageBackXUpDown.Value);
                            ImageDefn.Y  = decimal.ToInt32(ImageBackYUpDown.Value);
                            ImageDefn.P1 = decimal.ToInt32(ImageBackP1UpDown.Value);
                            ImageDefn.P2 = decimal.ToInt32(ImageBackP2UpDown.Value);

                            ImageDefn.Filename = ImageBackFileBox.Text;

                            //Call the SDK function to draw the image on the canvas
                            SDKReturn = SDK.ID_DrawImage(hSession,
                                                         ImageBackResin.Checked ? SDK.Canvas.BackResin : SDK.Canvas.Back,
                                                         ImageDefn);
                            if (SDKReturn != SDK.Return.Success)
                            {
                                HandleError("DrawImageBack", SDKReturn);
                                break;
                            }
                        }
                    }
                }

                //-------------------------------------------------------------------

                //Print the Card
                SDKReturn = SDK.ID_PrintCard(hSession);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("PrintCard", SDKReturn);
                    break;
                }

                //Wait for the printing to complete
                WaitForPrinterToFinish();

/*
                **************************************************************************************
                * Restore the settings for the print job, and for the card back, as saved previously *
                **************************************************************************************
                //Restore Original Print Settings
                SDKReturn = SDK.ID_PrintSettings(hSession, SDK.Action.Write, OldPrintSettings);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("RestorePrintSettings", SDKReturn);
                    break;
                }

                //Restore the Original Settings for the Back of the Card
                SDKReturn = SDK.ID_CardSettings(hSession, SDK.Action.Write, SDK.Side.Back, OldBackSettings);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("RestoreBackSettings", SDKReturn);
                }
*/
            } while (false);  //End of single pass do..while loop

            //All 'breaks' from the single pass do..while loop come here
            if (FrontDC      != IntPtr.Zero) SDK.ID_CanvasDelete(hSession, SDK.Canvas.Front);
            if (FrontResinDC != IntPtr.Zero) SDK.ID_CanvasDelete(hSession, SDK.Canvas.FrontResin);
            if (BackDC       != IntPtr.Zero) SDK.ID_CanvasDelete(hSession, SDK.Canvas.Back);
            if (BackResinDC  != IntPtr.Zero) SDK.ID_CanvasDelete(hSession, SDK.Canvas.BackResin);

            Cursor.Current = Cursors.Default;
        }

        #endregion === Print Button ===

        //----------------------------------------------------------------------

        #region === Printer Preferences ===

        [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true,
                   ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        private static extern int DocumentProperties(IntPtr hwnd,
                                                     IntPtr hPrinter,
                                                     [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName,
                                                     IntPtr pDevModeOutput,
                                                     IntPtr pDevModeInput,
                                                     int fMode);

        [DllImport("gdi32.dll", EntryPoint = "ExtEscape", SetLastError = true,
                   ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        private static extern int ExtEscape(IntPtr hdc,
                                            int nEscape,
                                            int cbInput,
                                            string lpszInData,
                                            int cbOutput,
                                            IntPtr lpszOutData);

        private const int DM_OUT_BUFFER = 2;
        private const int DM_IN_PROMPT = 4;
        private const int DM_IN_BUFFER = 8;

        [DllImport("kernel32.dll")]
        static extern IntPtr GlobalLock(IntPtr hMem);

        [DllImport("kernel32.dll")]
        static extern bool GlobalUnlock(IntPtr hMem);

        private void PrinterPrefs_Click(object sender, EventArgs e)
        {
            if (nativePrint.Checked)
            {
                //Use native Windows API calls, etc. to display and save printer 
                //preferences locally
                IntPtr hDevMode = ps.GetHdevmode(ps.DefaultPageSettings);
                IntPtr pDevMode = GlobalLock(hDevMode);
                int sizeNeeded = DocumentProperties(this.Handle,
                                                    IntPtr.Zero,
                                                    ps.PrinterName,
                                                    IntPtr.Zero,
                                                    pDevMode,
                                                    0);

                IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);
                DocumentProperties(this.Handle,
                                   IntPtr.Zero,
                                   ps.PrinterName,
                                   devModeData,
                                   pDevMode,
                                   DM_OUT_BUFFER | DM_IN_PROMPT | DM_IN_BUFFER);
                GlobalUnlock(hDevMode);

                //Update Printer Settings to save any changes made.
                ps.SetHdevmode(devModeData);
                ps.DefaultPageSettings.SetHdevmode(devModeData);

                Marshal.FreeHGlobal(devModeData);
            }
            else
            {
                //Use the SDK to display and save any changes to the printer preferences in the driver
                SDK.Return SDKReturn = SDK.ID_PrinterPrefs(hSession, this.Handle);
                if (SDKReturn != SDK.Return.Success)
                {
                    HandleError("PrinterPrefs", SDKReturn);
                }
            }
        }

        #endregion === Printer Preferences ===
    }
}
