using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace BulkPrinting
{
    public class Printer
    {
        public const string UNIDIRECTIONAL_ON = "\x1B\x55\x31";
        public const string UNIDIRECTIONAL_OFF = "\x1B\x55\x30";
        public const string CR = "\x0d";
        public const string LF = "\x0a";
        public const string FORMFEED = "\x0c";
        public const string LINESPACE18 = "\x1B\x30";
        public const string LINESPACE772 = "\x1B\x31";
        public const string CHARPITCHS1 = "\x1B\x37";
        public const string CHARPITCHS2 = "\x1B\x36";
        public const string CHARPITCHPUB = "\x1B\x21\x5a";
        public const string CHARPITCHS0 = "\x1B\x21\x40";
        public const string CHARPITCHPICO = "\x1B\x50";
        public const string CHARPITCHELITE = "\x1B\x4D";
        public const string CONDENSED = "\x1B\x0F";
        public const string INITIALISE_PRINTER = "\x1B\x40";
        public const string EMPHASISE_ON = "\x1B\x45";
        public const string EMPHASISE_OFF = "\x1B\x46";

        public const int JOB_CONTROL_DELETE = 5;

        // Structure and API declarions:
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class DOCINFOA
        {
            [MarshalAs(UnmanagedType.LPStr)] public string pDocName;
            [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile;
            [MarshalAs(UnmanagedType.LPStr)] public string pDataType;
        }
        [StructLayout(LayoutKind.Sequential)]
        private struct SYSTEMTIME
        {
            Int16 wYear;
            Int16 wMonth;
            Int16 wDayOfWeek;
            Int16 wDay;
            Int16 wHour;
            Int16 wMinute;
            Int16 wSecond;
            Int16 wMilliseconds;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        struct JOB_INFO_1
        {
            public UInt32 JobId;
            [MarshalAs(UnmanagedType.LPStr)] public string pPrinterName;
            [MarshalAs(UnmanagedType.LPStr)] public string pMachineName;
            [MarshalAs(UnmanagedType.LPStr)] public string pUserName;
            [MarshalAs(UnmanagedType.LPStr)] public string pDocument;
            [MarshalAs(UnmanagedType.LPStr)] public string pDatatype;
            [MarshalAs(UnmanagedType.LPStr)] public string pStatus;
            public UInt32 Status;
            public UInt32 Priority;
            public UInt32 Position;
            public UInt32 TotalPages;
            public UInt32 PagesPrinted;
            public SYSTEMTIME Submitted;
        }
        [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

        [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

        [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndDocPrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

        [DllImport("winspool.drv", EntryPoint = "GetJobA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        private static extern bool GetJob(IntPtr hPrinter, Int32 JobId, Int32 Level, out byte[] pJob, Int32 cbBuf, out Int32 pcbNeeded);

        [DllImport("winspool.drv", EntryPoint = "SetJobA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        private static extern bool SetJob(IntPtr hPrinter, int JobId, int Level, out byte pJob, int Command_Renamed);
        /*=================================================*/

        private IntPtr HandlePrinter;
        private PrinterSettings ps;

        public Printer()
        {
            HandlePrinter = IntPtr.Zero;
            ps = new PrinterSettings();
        }

        public string PrinterName
        {
            get
            {
                return ps.PrinterName;
            }
            set
            {
                ps.PrinterName = value;
            }
        }

        public bool ChoosePrinter()
        {
            PrintDialog pd = new PrintDialog();
            pd.UseEXDialog = true; //Required for AMD64 based processors
            pd.PrinterSettings = ps;
            if (pd.ShowDialog() == DialogResult.OK)
            {
                ps = pd.PrinterSettings;
                return true;
            }
            else
                return false;
        }

        public bool GetJobInfo(int JobID)
        {
            //JOB_INFO_1 JobInfo = new JOB_INFO_1();
            byte[] JobInfoByte;
            int pcbNeeded;
            if (HandlePrinter == IntPtr.Zero) return false;

            GetJob(HandlePrinter, JobID, 1, out JobInfoByte, 240, out pcbNeeded);
            return false;
        }

        public int Open(string DocName)
        {
            // see if printer is already open
            if (HandlePrinter != IntPtr.Zero) return 0;

            // opens the printer
            bool risp = OpenPrinter(ps.PrinterName, out HandlePrinter, IntPtr.Zero);
            if (risp == false) return 0;

            // starts a print job
            DOCINFOA MyDocInfo = new DOCINFOA();
            MyDocInfo.pDocName = DocName;
            MyDocInfo.pOutputFile = null;
            MyDocInfo.pDataType = "RAW";

            int JobID = StartDocPrinter(HandlePrinter, 1, MyDocInfo);
            if (JobID > 0)
            {
                StartPagePrinter(HandlePrinter); //starts a page       
            }
            return JobID;
        }

        public bool Close()
        {
            if (HandlePrinter == IntPtr.Zero) return false;
            if (!EndPagePrinter(HandlePrinter)) return false;
            if (!EndDocPrinter(HandlePrinter)) return false;
            if (!ClosePrinter(HandlePrinter)) return false;
            HandlePrinter = IntPtr.Zero;
            return true;
        }

        public bool Print(string outputstring)
        {
            if (HandlePrinter == IntPtr.Zero) return false;

            IntPtr buf = Marshal.StringToCoTaskMemAnsi(outputstring);

            Int32 done = 0;
            bool ok = WritePrinter(HandlePrinter, buf, outputstring.Length, out done);

            Marshal.FreeCoTaskMem(buf);

            if (!ok) return false;
            else return true;
        }

        public void NewPage()
        {
            EndPagePrinter(HandlePrinter);
            StartPagePrinter(HandlePrinter);
        }


        /****************************************************************************************************************************/



        private static PrintDocument pdoc = null;
        private static List<OrderList> OrderReportList;
        private static int ListLoc = 0;

        public static void PrintOrderReport(List<OrderList> OrderPrintList)
        {
            ListLoc = 0;
            OrderReportList = OrderPrintList;
            PrintDialog pd = new PrintDialog();
            pd.UseEXDialog = true; //Required for AMD64 based processors
            pdoc = new PrintDocument();
            PrinterSettings ps = new PrinterSettings();
            Font font = new Font("Courier New", 15);


            PaperSize psize = new PaperSize("Custom", 100, 200);

            pd.Document = pdoc;
            pd.Document.DefaultPageSettings.PaperSize = psize;
            pdoc.DefaultPageSettings.PaperSize.Height = 820;

            pdoc.DefaultPageSettings.PaperSize.Width = 520;

            pdoc.PrintPage += new PrintPageEventHandler(pdoc_PrintPage);
            DialogResult result = pd.ShowDialog();
            if (result == DialogResult.OK)
            {
                pdoc.DefaultPageSettings.PrinterSettings.PrintRange = pd.PrinterSettings.PrintRange;
                /*
                PrintPreviewDialog pp = new PrintPreviewDialog();
                pp.Document = pdoc;
                result = pp.ShowDialog();
                if (result == DialogResult.OK)
                {
                */
                    pdoc.Print();
                //}
            }

        }

        class Columns
        {
            public static int OrderDate = 0;
            public static int OrderReference = 90;
            public static int User = 170;
            public static int OrderItems = 290;
            public static int QtyOrdered = 430;
            public static int QtyDelivered = 500;
            public static int Cost = 580;
            public static int Balance = 630;
        }

        public static void pdoc_PrintPage(object sender, PrintPageEventArgs e)
        {
            //Header
            Graphics graphics = e.Graphics;
            Font font = new Font("Arial", 10);
            float fontHeight = font.GetHeight();
            int startX = 50;
            int startY = 55;
            int Offset = 40;

            var a = Globals.SessionData.AccessToken;

            graphics.DrawString("R-Group Order Report", new Font("Arial", 28), new SolidBrush(Color.Black), startX, startY + Offset);
            graphics.DrawString(Globals.SessionData.Credentials.Payload.User.Account.Name, new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + 500, startY + Offset);
            graphics.DrawString(Globals.SessionData.Credentials.Payload.User.FirstName + " " + Globals.SessionData.Credentials.Payload.User.Surname, new Font("Arial", 10), new SolidBrush(Color.Black), startX + 500, startY + Offset + 20);
            graphics.DrawString(DateTime.Now.ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), startX + 500, startY + Offset + 40);

            Offset = Offset + 90;

            graphics.DrawString("Date", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.OrderDate, startY + Offset);
            graphics.DrawString("Reference", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.OrderReference, startY + Offset);
            graphics.DrawString("User", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.User, startY + Offset);
            graphics.DrawString("Items", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.OrderItems, startY + Offset);
            graphics.DrawString("Ordered", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.QtyOrdered, startY + Offset);
            graphics.DrawString("Delivered", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.QtyDelivered, startY + Offset);
            graphics.DrawString("Cost", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.Cost, startY + Offset);
            graphics.DrawString("Balance", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.Balance, startY + Offset);
            graphics.DrawLine(new Pen(Color.Black, 2), new Point(startX, startY + Offset + 20), new Point(startX + 700, startY + Offset + 20));
            Offset = Offset + 10;

            while (ListLoc < OrderReportList.Count)
            {
                Offset = Offset + 40;

                graphics.DrawString(OrderReportList[ListLoc].OrderDate, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.OrderDate, startY + Offset);
                graphics.DrawString(OrderReportList[ListLoc].OrderReference, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.OrderReference, startY + Offset);
                graphics.DrawString(OrderReportList[ListLoc].User, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.User, startY + Offset);

                foreach (OrderReportLine OrderLine in OrderReportList[ListLoc].OrderLines)
                {
                    graphics.DrawString(OrderLine.OrderItem, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.OrderItems, startY + Offset);
                    graphics.DrawString(OrderLine.QtyOrdered, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.QtyOrdered, startY + Offset);
                    graphics.DrawString(OrderLine.QtyDelivered, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.QtyDelivered, startY + Offset);
                    graphics.DrawString(OrderLine.Cost, new Font("Arial", 10), new SolidBrush(Color.Black), startX + Columns.Cost, startY + Offset);
                    Offset = Offset + 20;
                }

                graphics.DrawString("Total", new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.QtyDelivered, startY + Offset);
                graphics.DrawString(OrderReportList[ListLoc].OrderCost, new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.Cost, startY + Offset);
                graphics.DrawString(OrderReportList[ListLoc].Balance, new Font("Arial", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX + Columns.Balance, startY + Offset);
                ListLoc += 1;

                if (Offset > 800)
                {
                    Offset = 50;
                    e.HasMorePages = true;
                    continue;
                }
            }
        }
    }

}