using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SQLite;
using System.Drawing;
using System.Globalization;
using System.Security.Permissions;
using System.Windows.Forms;

namespace BulkPrinting
{
    public partial class BatchForm : ObservedForm
    {
        private BatchDownloader BatchDownloader;
        private DownloadedLogSummariser DownloadedLogSummariser;

        public BatchForm()
        {
            InitializeComponent();
        }

        public void PopulateGrid()
        {
            bool CanOrder = Utility.CheckUserAccess(Utility.UserPermissions.BulkOrder);
            bool CanExport = Utility.CheckUserAccess(Utility.UserPermissions.BulkExport);
            dgvBatches.Rows.Clear();
            dgvBatches.Columns.Clear();

            dgvBatches.Columns.Add("Id", "ID");
            dgvBatches.Columns.Add("OrderDate", "Order Date");
            if (CanOrder) dgvBatches.Columns.Add("OrderReference", "Customer Reference");
            if (CanOrder) dgvBatches.Columns.Add("InternalReference", "Order Reference");
            dgvBatches.Columns.Add("NetworkName", "Network Name");
            dgvBatches.Columns.Add("ProductDescription", "Product Description");
            dgvBatches.Columns.Add("VoucherType", "Voucher Type");
            dgvBatches.Columns.Add("FaceValue", "Face Value");
            if (CanOrder) dgvBatches.Columns.Add("RequestedQuantity", "Quantity Ordered");
            dgvBatches.Columns.Add("DeliveredQuantity", "Quantity Delivered");
            if (CanOrder) dgvBatches.Columns.Add("ReadyForDownload", "Batch Ready for Download");
            dgvBatches.Columns.Add("Downloaded", "Downloaded");
            dgvBatches.Columns.Add("PrintedQuantity", "Quantity Printed");
            if (CanExport) dgvBatches.Columns.Add("Exported", "Exported Batch");
            var Sql = "Select Id,OrderDate,OrderReference,InternalReference,NetworkName,ProductDescription,VoucherType,FaceValue,RequestedQuantity,DeliveredQuantity,ReadyForDownload,Downloaded,PrintCount,ReprintCount,ExportCount,ReExportCount From Batch WHERE OrderDate BETWEEN @startdate AND @enddate";

            //Sql = "Select Id,OrderDate,OrderReference,InternalReference,NetworkName,ProductDescription,VoucherType,FaceValue,RequestedQuantity,DeliveredQuantity,ReadyForDownload,Downloaded,(SELECT COUNT(*) FROM Voucher WHERE Voucher.BatchId=Batch.Id) AS VoucherCount From Batch WHERE OrderDate BETWEEN @startdate AND @enddate";
            //dgvBatches.Columns.Add("VoucherCount", "Voucher Count");

            CultureInfo IVC = CultureInfo.InvariantCulture;
            using (var Command = Globals.DB.CreateCommand(Sql,
                new SQLiteParameter("@startdate", dtpFilterStartDate.Value.Date.ToString("yyyy-MM-dd 00:00:00", IVC)),
                new SQLiteParameter("@enddate", dtpFilterEndDate.Value.Date.ToString("yyyy-MM-dd 23:59:59", IVC))))
            {
                lblLoading.Hide();
                using (SQLiteDataReader read = Command.ExecuteReader())
                {
                    while (read.Read())
                    {
                        int BatchId = int.Parse(read["Id"].ToString());
                        int DeliveredQuantity = int.Parse(read["DeliveredQuantity"].ToString());
                        int PrintCount = (int)read["PrintCount"];
                        int ReprintCount = (int)read["ReprintCount"];
                        int ExportCount = (int)read["ExportCount"];
                        int ReExportCount = (int)read["ReExportCount"];


                        //Filters to exclude rows that don't match
                        if (rdoFilterPrinted.Checked)
                        {
                            if (PrintCount == 0)
                            {
                                continue;
                            }
                        }
                        if (rdoFilterUnprinted.Checked)
                        {
                            if (PrintCount >= DeliveredQuantity)
                            {
                                continue;
                            }
                        }
                        if (rdoFilterReprinted.Checked)
                        {
                            if (ReprintCount == 0)
                            {
                                continue;
                            }
                        }
                        if (rdoFilterExported.Checked)
                        {
                            if (ExportCount == 0)
                            {
                                continue;
                            }
                        }
                        else
                        {
                            if (ExportCount > 0)
                            {
                                continue;
                            }
                        }

                        var BatchRow = new List<object>
                            {
                                BatchId,
                                read["OrderDate"]
                            };
                        if (CanOrder)
                        {
                            BatchRow.Add(read["OrderReference"]);
                            BatchRow.Add(read["InternalReference"]);
                        }
                        BatchRow.Add(read["NetworkName"].ToString());
                        BatchRow.Add(read["ProductDescription"].ToString());
                        BatchRow.Add(Enum.Parse(typeof(Vouchertype), read["VoucherType"].ToString()).ToString());
                        BatchRow.Add("R" + ((decimal)read["FaceValue"]).ToString("0.##"));

                        if (CanOrder)
                            BatchRow.Add(read["RequestedQuantity"]);

                        BatchRow.Add(read["DeliveredQuantity"]);

                        if (CanOrder)
                            BatchRow.Add(((bool)read["ReadyForDownload"] == true ? "Yes" : "No"));

                        BatchRow.Add((bool)read["Downloaded"] ? "Yes" : "No");
                        BatchRow.Add(PrintCount);

                        if (CanExport)
                            BatchRow.Add(ExportCount > 0 ? "Exported" : "");

                        //BatchRow.Add(read["VoucherCount"]);

                        dgvBatches.Rows.Add(BatchRow.ToArray());
                    }
                    dgvBatches.Sort(dgvBatches.Columns["OrderDate"], ListSortDirection.Descending);
                }
            }
        }

        private void BatchForm_Load(object sender, EventArgs e)
        {
            List<Button> LeftButtonList = new List<Button>();
            List<Button> RightButtonList = new List<Button>();
            LeftButtonList.Add(this.btnLogout);
            LeftButtonList.Add(this.btnOrderReport);
            LeftButtonList.Add(this.btnOrder);
            LeftButtonList.Add(this.btnPrint);
            LeftButtonList.Add(this.btnExport);
            RightButtonList.Add(this.btnViewPINs);
            RightButtonList.Add(this.btnReExport);
            RightButtonList.Add(this.btnReprint);
            foreach (Button b in LeftButtonList) {
                b.Hide();
            }
            foreach (Button b in RightButtonList) {
                b.Hide();
            }

            if (Globals.SessionMode == SessionModes.Online)
            {
                if (!Utility.CheckUserAccess(Utility.UserPermissions.BulkOrder))
                    LeftButtonList.Remove(this.btnOrder);

                if (!Utility.CheckUserAccess(Utility.UserPermissions.CanPrintOnline))
                    LeftButtonList.Remove(this.btnPrint);

                if (!Utility.CheckUserAccess(Utility.UserPermissions.CanReprintOnline)) {
                    RightButtonList.Remove(this.btnReprint);
                    rdoFilterReprinted.Hide();
                }

            }
            else if (Globals.SessionMode == SessionModes.Offline)
            {
                LeftButtonList.Remove(this.btnOrder);
                if (!Utility.CheckUserAccess(Utility.UserPermissions.CanPrintOffline))
                    LeftButtonList.Remove(this.btnPrint);

                if (!Utility.CheckUserAccess(Utility.UserPermissions.CanReprintOffline)) { 
                    RightButtonList.Remove(this.btnReprint);
                    rdoFilterReprinted.Hide();
                }
            }
            if (!Utility.CheckUserAccess(Utility.UserPermissions.BulkExport)) {
                LeftButtonList.Remove(this.btnExport);
                RightButtonList.Remove(this.btnReExport);
                rdoFilterExported.Hide();
            }

            if (!Utility.CheckUserAccess(Utility.UserPermissions.BulkViewPins))
                RightButtonList.Remove(this.btnViewPINs);

            int ButtonX = btnLogout.Location.X;
            int ButtonY = btnLogout.Location.Y;
            int ButtonSpacing = btnOrderReport.Location.X - ButtonX;
            foreach (Button b in LeftButtonList)
            {
                b.Location = new Point(ButtonX, ButtonY);
                b.Show();
                ButtonX += ButtonSpacing;
            }

            ButtonX = btnReprint.Location.X;
            RightButtonList.Reverse();
            foreach (Button b in RightButtonList)
            {
                b.Location = new Point(ButtonX, ButtonY);
                b.Show();
                ButtonX -= ButtonSpacing;
            }

            lblLoading.Show();
            dtpFilterStartDate.Value = DateTime.Now.AddMonths(-3);
            Globals.OpenBatches = new List<int>();

            var hwnd = new System.Runtime.InteropServices.HandleRef(this, Handle);
            BatchDownloader = new BatchDownloader(
                Globals.DB,
                () =>
                {
                    // Refresh grid

                    // DO NOT use Invoke as this can cause a deadlock if we are attempting to join the BatchDownloader after a cancel.
                    // Also, use PostMessage rather than SendMessage as PostMessage doesn't wait for the message to be processed and
                    // therefore won't block.
                    Utility.PostMessage(hwnd, Utility.WM_USER, IntPtr.Zero, IntPtr.Zero);
                },
                () =>
                {
                    // Trigger download log summarisation
                    Utility.PostMessage(hwnd, Utility.WM_USER + 1, IntPtr.Zero, IntPtr.Zero);
                });
            BatchDownloader.Start();

            Utility.InitialiseUserLimits(Globals.DB);

            PopulateGrid();
        }

        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == Utility.WM_USER)
            {
                PopulateGrid();
                return;
            }
            else if (m.Msg == Utility.WM_USER + 1)
            {
                TriggerDownloadedLogSummarisation();
                return;
            }
            base.WndProc(ref m);
        }

        private void TriggerDownloadedLogSummarisation()
        {
            if (DownloadedLogSummariser == null)
            {
                var hwnd = new System.Runtime.InteropServices.HandleRef(this, Handle);

                DownloadedLogSummariser = new DownloadedLogSummariser(
                    Globals.DB,
                    () =>
                    {
                        // Refresh grid

                        // DO NOT use Invoke as this can cause a deadlock if we are attempting to join the BatchDownloader after a cancel.
                        // Also, use PostMessage rather than SendMessage as PostMessage doesn't wait for the message to be processed and
                        // therefore won't block.
                        Utility.PostMessage(hwnd, Utility.WM_USER, IntPtr.Zero, IntPtr.Zero);
                    });

                DownloadedLogSummariser.Start();
            }
        }

        public void NewBatchAvailable()
        {
            BatchDownloader.CheckForNewBatches();
        }

        private void btnOrder_Click(object sender, EventArgs e)
        {
            OrderForm orderform = new OrderForm();
            orderform.SourceForm = this;
            orderform.Show();
        }

        private void btnPrint_Click(object sender, EventArgs e)
        {
            if (dgvBatches.SelectedRows.Count == 0)
            {
                MessageBox.Show("Please choose a batch to print.", "No batch selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            if ((string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["Exported"].Index].Value != "")
            {
                MessageBox.Show("This batch has been exported previously. Exported batches cannot be printed.", "Cannot print batch", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            if (Utility.CheckUserAccess(Utility.UserPermissions.BulkOrder)) { //Only check for undownloaded vouchers if the user is able to see them
                if ((string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["ReadyForDownload"].Index].Value == "No") {
                    MessageBox.Show("This batch is not fully downloaded and cannot be printed.\nPlease wait until \"Batch Ready For Download\" says Yes.\nThis may take several minutes depending on the size of\nthe order and available stock.", "Cannot print batch", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
            }


            int BatchID = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["Id"].Index].Value;
            if (Globals.OpenBatches.Contains(BatchID)) {
                MessageBox.Show("A print dialog is already open for this batch","Cannot open print dialog",MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
                return;
            }

            int DeliveredVoucherCount = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["DeliveredQuantity"].Index].Value;
            int DownloadedVoucherCount = Convert.ToInt32(Globals.DB.ExecuteScalar(
                "SELECT COUNT(*) FROM Voucher WHERE BatchId=@id",
                new SQLiteParameter("@id", BatchID)));
            if (DownloadedVoucherCount < DeliveredVoucherCount) {
                MessageBox.Show(string.Format("Batch {0} has not finished downloading.\nDownloaded {1} of {2} vouchers in batch.",BatchID,DownloadedVoucherCount,DeliveredVoucherCount), "Cannot open print dialog", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }


            this.BeginInvoke((Action)delegate {
                PrintForm PrintFormInstance = new PrintForm();
                Globals.OpenBatches.Add(BatchID);
                int TotalVouchers = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["DeliveredQuantity"].Index].Value;
                int VouchersPrinted = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["PrintedQuantity"].Index].Value;

                PrintFormInstance.PrintDescription=(string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["ProductDescription"].Index].Value;
                PrintFormInstance.BatchOrderDate=(DateTime)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["OrderDate"].Index].Value;
                PrintFormInstance.UnprintedVouchers= TotalVouchers-VouchersPrinted;
                PrintFormInstance.TotalVouchers=TotalVouchers;
                PrintFormInstance.FaceValue=(string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["FaceValue"].Index].Value;
                PrintFormInstance.VoucherTypeName=(string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["VoucherType"].Index].Value;
                PrintFormInstance.BatchID=BatchID;
                PrintFormInstance.NetworkName = (string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["NetworkName"].Index].Value;

                PrintFormInstance.Show();
            });
        }

        private void btnLogout_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void pnlSplitGrids_Paint(object sender, PaintEventArgs e)
        {

        }

        private void BatchForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Globals.OpenBatches.Count > 0) {
                MessageBox.Show("There are printing jobs in progress - pelase wait for them to complete before logging out.", "Busy printing", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                e.Cancel = true;
                return;
            }

            if (BatchDownloader != null)
            {
                BatchDownloader.Cancel();
            }
            if (DownloadedLogSummariser != null)
            {
                DownloadedLogSummariser.Cancel();
            }

            if (BatchDownloader != null)
            {
                BatchDownloader.Join();
            }
            if (DownloadedLogSummariser != null)
            {
                DownloadedLogSummariser.Join();
            }

            Utility.Logout();
        }

        private void LogoutTimer_Tick(object sender, EventArgs e)
        {
            Utility.Logout();
        }

        public void ResetTimer()
        {
            LogoutTimer.Stop();
            LogoutTimer.Start();
        }

        private void btnReExport_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Please be aware that this function is used for exporting vouchers that have already been exported previously. Use this function with caution.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            ExportForm exportform = new ExportForm(ExportForm.ExportMode.Reexport);
            exportform.Show();
        }

        private void dtpFilterStartDate_CloseUp(object sender, EventArgs e)
        {
            PopulateGrid();
        }

        private void dtpFilterEndDate_CloseUp(object sender, EventArgs e)
        {
            PopulateGrid();
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            ExportForm exportform = new ExportForm(ExportForm.ExportMode.Export);
            exportform.Show();
        }

        private void dgvBatches_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void rdoFilterUnprinted_CheckedChanged(object sender, EventArgs e)
        {
            if (rdoFilterUnprinted.Checked)
            {
                PopulateGrid();
                btnPrint.Enabled = true;
                btnReprint.Enabled = false;
            }
        }

        private void rdoFilterPrinted_CheckedChanged(object sender, EventArgs e)
        {
            if (rdoFilterPrinted.Checked)
            {
                PopulateGrid();
                btnPrint.Enabled = false;
                btnReprint.Enabled = true;
            }
        }

        private void rdoFilterReprinted_CheckedChanged(object sender, EventArgs e)
        {
            if (rdoFilterReprinted.Checked)
            {
                PopulateGrid();
                btnPrint.Enabled = false;
                btnReprint.Enabled = true;
            }
        }

        private void rdoFilterExported_CheckedChanged(object sender, EventArgs e)
        {
            if (rdoFilterExported.Checked)
            {
                PopulateGrid();
                btnPrint.Enabled = false;
                btnReprint.Enabled = false;
            }
        }

        private void btnOrderReport_Click(object sender, EventArgs e)
        {
            OrderReport OrderReportForm = new OrderReport();
            OrderReportForm.Show();
        }

        private void btnReprint_Click(object sender, EventArgs e)
        {
            if (dgvBatches.SelectedRows.Count == 0) {
                MessageBox.Show("Please choose a batch to reprint.", "No batch selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            MessageBox.Show("Please be aware that this function is used for reprinting vouchers that have already been printed previously. Use this function with caution.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            int BatchID = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["Id"].Index].Value;
            if ((string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["Exported"].Index].Value != "")
            {
                MessageBox.Show("This batch has been exported previously. Exported batches cannot be printed.", "Cannot print batch", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            int PrintCount = int.Parse(Globals.DB.ExecuteScalar(
                "SELECT COUNT(*) FROM Voucher v LEFT JOIN Logs l ON v.Id = l.VoucherId AND l.EventType = @eventtype WHERE l.VoucherId IS NOT NULL AND v.BatchId=@batchid AND Retry=0",
                new SQLiteParameter("@batchid", BatchID),
                new SQLiteParameter("@eventtype", VendorEvent.VendorEventType.PrintVoucher)).ToString());

            if (PrintCount == 0) {
                MessageBox.Show("You can only use the Reprint feature for vouchers that have already been printed. Please choose a batch with previously printed vouchers.", "Cannot reprint batch", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            int DeliveredVoucherCount = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["DeliveredQuantity"].Index].Value;
            int DownloadedVoucherCount = Convert.ToInt32(Globals.DB.ExecuteScalar(
                "SELECT COUNT(*) FROM Voucher WHERE BatchId=@id",
                new SQLiteParameter("@id", BatchID)));
            if (DownloadedVoucherCount < DeliveredVoucherCount)
            {
                MessageBox.Show(string.Format("Batch {0} has not finished downloading.\nDownloaded {1} of {2} vouchers in batch.", BatchID, DownloadedVoucherCount, DeliveredVoucherCount), "Cannot open print dialog", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }


            if (Utility.CheckUserAccess(Utility.UserPermissions.BulkOrder))
            { //Only check for undownloaded vouchers if the user is able to see them
                if ((string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["ReadyForDownload"].Index].Value == "No")
                {
                    MessageBox.Show("This batch is not ready to downloaded and cannot be printed.", "Cannot print batch", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
            }


            if (Globals.OpenBatches.Contains(BatchID))
            {
                MessageBox.Show("A print dialog is already open for this batch", "Cannot open print dialog", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            this.BeginInvoke((Action)delegate {
                ReprintForm PrintFormInstance = new ReprintForm();
                Globals.OpenBatches.Add(BatchID);
                int TotalVouchers = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["DeliveredQuantity"].Index].Value;
                int VouchersPrinted = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["PrintedQuantity"].Index].Value;

                PrintFormInstance.PrintDescription = (string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["ProductDescription"].Index].Value;
                PrintFormInstance.BatchOrderDate = (DateTime)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["OrderDate"].Index].Value;
                PrintFormInstance.UnprintedVouchers = TotalVouchers - VouchersPrinted;
                PrintFormInstance.TotalVouchers = TotalVouchers;
                PrintFormInstance.FaceValue = (string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["FaceValue"].Index].Value;
                PrintFormInstance.VoucherTypeName = (string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["VoucherType"].Index].Value;
                PrintFormInstance.BatchID = BatchID;
                PrintFormInstance.NetworkName = (string)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["NetworkName"].Index].Value;

                PrintFormInstance.Show();
            });

        }

        private void btnViewPINs_Click(object sender, EventArgs e)
        {
            VoucherForm ViewPINs = new VoucherForm();
            if (dgvBatches.SelectedRows.Count == 0)
            {
                ViewPINs.BatchID = 0;
            }
            else
            {
                ViewPINs.BatchID = (int)dgvBatches.SelectedRows[0].Cells[dgvBatches.Columns["Id"].Index].Value;
            }
            ViewPINs.Show();
        }

        private void btn_Paint(object sender, PaintEventArgs e)
        {
            Button b = sender as Button;
            if (!b.Enabled)
            {
                e.Graphics.Clear(Color.Gray);
                //e.Graphics.DrawImage(b.BackgroundImage, e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height);
                e.Graphics.DrawImage(b.BackgroundImage, b.ClientRectangle);
            }
        }
    }
}
