using FastReport.Barcode;
using FastReport.Controls;
using FastReport.Design.PageDesigners.Page;
using FastReport.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FastReport.Forms
{
    internal partial class CISWizardForm : BaseDialogForm
    {
        const string MARKIROVKA_URL = "http://check.markirovka.nalog.ru/kc/?kiz=";

        private Report report;
        private PrinterSettings printerSettings;
        private Report sampleReport;
        Border border;
        bool update;

        private void CbxType_SelectedIndexChanged(object sender, EventArgs e)
        {
            cbxMethodСirculation.Visible = false;
            cbxSize.Visible = false;
            cbLeftMargin.Visible = false;
            tbCountry.Visible = false;
            tbID.Visible = false;

            lbMethodСirculation.Visible = false;
            lbCountry.Visible = false;
            lbID.Visible = false;
            lbSize.Visible = false;
            lbData.Visible = false;
            tbData.Visible = false;
            cbxTypeBarcodes.Visible = false;
            lbTypeBarcodes.Visible = false;
            switch (cbxType.SelectedIndex)
            {
                case 2:
                    lbData.Visible = true;
                    tbData.Visible = true;
                    cbxTypeBarcodes.Visible = true;
                    lbTypeBarcodes.Visible = true;
                    cbxTypeBarcodes.Items.Clear();
                    cbxTypeBarcodes.Items.AddRange(new object[] 
                    { 
                        "GS1-128 (UCC/EAN-128)",
                        "Datamatrix" 
                    });
                    cbxTypeBarcodes.SelectedIndex = 0;
                    break;
                case 5:
                    lbData.Visible = true;
                    tbData.Visible = true;
                    cbxTypeBarcodes.Visible = true;
                    lbTypeBarcodes.Visible = true;
                    cbxTypeBarcodes.Items.Clear();
                    cbxTypeBarcodes.Items.AddRange(new object[] 
                    { 
                        "Datamatrix",
                        "QR Code"
                    });
                    cbxTypeBarcodes.SelectedIndex = 0;
                    break;
                case 6:
                    cbxMethodСirculation.Visible = true;
                    cbxSize.Visible = true;
                    cbLeftMargin.Visible = true;
                    tbCountry.Visible = true;
                    tbID.Visible = true;

                    lbMethodСirculation.Visible = true;
                    lbCountry.Visible = true;
                    lbID.Visible = true;
                   
                    lbSize.Visible = true;
                    break;
                case 10:
                    lbData.Visible = true;
                    tbData.Visible = true;
                    cbxTypeBarcodes.Visible = true;
                    lbTypeBarcodes.Visible = true;
                    cbxTypeBarcodes.Items.Clear();
                    cbxTypeBarcodes.Items.AddRange(new object[] 
                    { 
                        "Code39",
                        "GS1-128 (UCC/EAN-128)",
                        "PDF417",
                        "MaxiCode",
                        "QR Code" 
                    });
                    cbxTypeBarcodes.SelectedIndex = 0;
                    break;
                default:
                    lbData.Visible = true;
                    tbData.Visible = true;
                    break;
            }
            UpdateSample();
        }

        private void Tb_ButtonClick(object sender, EventArgs e)
        {
            using (TextEditorForm form = new TextEditorForm(report))
            {
                form.ExpressionText = (sender as TextBoxButton).Text;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    (sender as TextBoxButton).Text = form.ExpressionText;
                    UpdateSample();
                }
            }
        }

        private void BtnBorder_Click(object sender, EventArgs e)
        {
            using (BorderEditorForm form = new BorderEditorForm())
            {
                form.Border = border;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    border = form.Border;
                }
            }
        }

        private void TbCountry_TextChanged(object sender, EventArgs e)
        {
            tbCountry.Text.ToUpper();
        }

        private void CISWizardForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (DialogResult == DialogResult.OK)
                Done();
        }

        /// <inheritdoc/>
        public override void UpdateDpiDependencies()
        {
            base.UpdateDpiDependencies();
            tbID.Image = GetImage(68); 
            tbData.Image = GetImage(68);
        }

        private void Done()
        {
            SetUpPapper(CreateReport());
            // tell the designer to reflect changes
            report.Designer.SetModified(null, "ChangeReport");
        }

        private DataBand CreateReport()
        {
            DataBand band = new DataBand();
            if (cbxType.SelectedIndex == 6) 
            {
                Report report = DialogResult == DialogResult.OK ? this.report : sampleReport;
                report.Load(ResourceLoader.GetStream("CIS.frx"));
                band = (report.FindObject("Data1") as DataBand);

                BarcodeObject code128 = (BarcodeObject)report.FindObject("Code128");
                code128.Text = tbID.Text == "" ? code128.Barcode.GetDefaultValue() : tbID.Text;
                (code128.Barcode as Barcode128).Initialize(code128.Text, false, 0, 1);
                SizeF code128NewBounds = (code128.Barcode as Barcode128).CalcBounds();
                code128.Zoom = code128.Bounds.Width / code128NewBounds.Width;

                TextObject code128Text = (TextObject)report.FindObject("Code128Text");
                code128Text.Text = "№: " + code128.Text;

                BarcodeObject qr = (BarcodeObject)report.FindObject("QR");
                qr.Text = MARKIROVKA_URL + code128.Text;
                (qr.Barcode as BarcodeQR).Initialize(qr.Text, false, 0, 1);
                SizeF QRNewBounds = (qr.Barcode as BarcodeQR).CalcBounds();
                qr.Zoom = qr.Bounds.Height / QRNewBounds.Height;

                TextObject country = (TextObject)report.FindObject("Country");
                country.Text = tbCountry.Text;
                if (cbxMethodСirculation.SelectedIndex == 1)
                {
                    (report.FindObject("Arrow") as ReportComponentBase).Visible = false;
                    (report.FindObject("Shape1") as ReportComponentBase).FillColor = Color.ForestGreen;
                }
                else
                {
                    (report.FindObject("Arrow") as ReportComponentBase).Visible = true;
                    (report.FindObject("Shape1") as ReportComponentBase).Visible = true;
                }

                if (cbxSize.SelectedIndex == 0)
                {
                    if (cbLeftMargin.Checked)
                    {
                        foreach (Base item in band.AllObjects)
                        {
                            if (item is ReportComponentBase)
                            {
                                (item as ReportComponentBase).Left += Units.Millimeters * 10;
                            }
                        }
                    }
                }
                else
                {
                    //(report.Pages[0] as ReportPage).PaperHeight = 25;
                    (report.FindObject("Data1") as BandBase).Height = 2.5f * 37.8f;

                    code128Text.Bounds = new RectangleF(311.85f, 0, 283.5f, 35.91f);
                    code128.Bounds = new RectangleF(311.85f, 37.8f, 283.37f, 45.36f);
                    (report.FindObject("Shape1") as ReportComponentBase).Height -= 0.3f * 38;
                    if (cbLeftMargin.Checked)
                    {
                        foreach (Base item in band.AllObjects)
                        {
                            if (item is ReportComponentBase)
                            {
                                (item as ReportComponentBase).Left += Units.Millimeters * 10;
                            }
                        }
                    }
                }
            }
            else 
            {
                BarcodeObject barcode = new BarcodeObject();
                string barcodeType = "Datamatrix";
                if (cbxTypeBarcodes != null && (cbxType.SelectedIndex == 2 || cbxType.SelectedIndex == 5 || cbxType.SelectedIndex == 10))
                {
                    barcodeType = cbxTypeBarcodes.SelectedItem.ToString();
                }
                barcode.Barcode = (BarcodeBase)Activator.CreateInstance(Barcodes.GetType(barcodeType));

                if (tbData.Text != null && tbData.Text != "")
                    barcode.Text = tbData.Text;
                else
                    barcode.Text = barcode.Barcode.GetDefaultValue();

                if (barcode.Barcode is LinearBarcodeBase)
                {
                    barcode.Height = Units.Millimeters * 25;
                    barcode.Padding = new Padding((int)(Units.Millimeters * 6.4), 0, (int)(Units.Millimeters * 6.4), 0);
                }
                else
                {
                    barcode.Padding = new Padding((int)(Units.Millimeters * 2));
                }
                barcode.Parent = band;
                barcode.UpdateAutoSize();
                barcode.Name = barcodeType;
            }
            
            return band;
        }
        
        private void OnChangeControl(object sender, EventArgs e)
        {
            UpdateSample();
        }

        private float ConvertUnitsToMillimeters(string value)
        {
            float floatValue = Converter.StringToFloat(value, true);
            switch (ReportWorkspace.Grid.GridUnits)
            {
                case PageUnits.Centimeters:
                    floatValue *= 10f;
                    break;

                case PageUnits.HundrethsOfInch:
                    floatValue *= 0.254f;
                    break;

                case PageUnits.Inches:
                    floatValue *= 25.4f;
                    break;

                case PageUnits.Millimeters:
                    // do nothing
                    break;
            }

            return floatValue;
        }

        private void SetUpPapper(DataBand band)
        {
            ReportPage page = report.Pages[0] as ReportPage;
            // setup paper
            if(cbxType.SelectedIndex != 6) // avoid clear page for fur
                page.Clear();
            page.Landscape = cbLandscape.Checked;
            page.PaperWidth = ConvertUnitsToMillimeters(tbPageWidth.Text);
            page.PaperHeight = ConvertUnitsToMillimeters(tbPageHeight.Text);
            page.LeftMargin = ConvertUnitsToMillimeters(tbMarginLeft.Text);
            page.TopMargin = ConvertUnitsToMillimeters(tbMarginTop.Text);

            // setup data band
            page.Bands.Add(band);
            band.Columns.Count = (int)nudCountColumns.Value;
            band.RowCount = (int)nudCountColumns.Value * (int)nudCountRows.Value;
            band.Columns.Width = GetWidthBand(band) + ConvertUnitsToMillimeters(tbHorizontalPadding.Text) * Units.Millimeters;
            band.CanGrow = true;
            band.Border = border;
            band.CreateUniqueName();
            band.CalcHeight();
            band.Height += ConvertUnitsToMillimeters(tbVerticalPadding.Text) * Units.Millimeters;
        }

        private void cbxPaper_SelectedIndexChanged(object sender, EventArgs e)
        {
            foreach (PaperSize ps in printerSettings.PaperSizes)
            {
                if (ps.PaperName == (string)cbxPaper.SelectedItem)
                {
                    float psWidth = ps.Width / 100f * 25.4f;
                    float psHeight = ps.Height / 100f * 25.4f;
                    if (ps.Kind == PaperKind.A4)
                    {
                        psWidth = 210;
                        psHeight = 297;
                    }
                    if (cbLandscape.Checked)
                    {
                        float ex = psWidth;
                        psWidth = psHeight;
                        psHeight = ex;
                    }

                    // avoid reset papersize to custom
                    update = true;
                    tbPageWidth.Text = psWidth.ToString();
                    tbPageHeight.Text = psHeight.ToString();
                    update = false;
                    break;
                }
            }
            UpdateSample();
        }

        private string GetUnits()
        {
            string unit = "";
            switch (ReportWorkspace.Grid.GridUnits)
            {
                case PageUnits.Millimeters:
                    unit = Res.Get("Misc,ShortUnitsMm");
                    break;
                case PageUnits.Centimeters:
                    unit = Res.Get("Misc,ShortUnitsCm");
                    break;
                case PageUnits.Inches:
                    unit = Res.Get("Misc,ShortUnitsIn");
                    break;
                case PageUnits.HundrethsOfInch:
                    unit = Res.Get("Misc,ShortUnitsHi");
                    break;
            }
            return unit;
        }

        private void CbLandscape_CheckedChanged(object sender, System.EventArgs e)
        {
            if (update)
                return;
            string w = tbPageWidth.Text;
            string h = tbPageHeight.Text;

            // avoid reset papersize to custom
            update = true;
            tbPageWidth.Text = h;
            tbPageHeight.Text = w;
            update = false;
            UpdateSample();
        }

        private void TbPageProps_TextChanged(object sender, System.EventArgs e)
        {
            if (update)
                return;
            cbxPaper.SelectedIndex = 0;
            UpdateSample();
        }

        private void TbWithUnits_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            e.Handled = !char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.' && e.KeyChar != ',' && e.KeyChar != ' ';
        }

        private void UpdateSample()
        {
            DataBand band1 = CreateReport();
            band1.CanGrow = true;
            band1.CalcHeight();
            float widthBands = GetWidthBand(band1);
            ReportPage page = sampleReport.Pages[0] as ReportPage;
            page.Clear();
            page.Landscape = cbLandscape.Checked;
            page.PaperWidth = ConvertUnitsToMillimeters(tbPageWidth.Text);
            page.PaperHeight = ConvertUnitsToMillimeters(tbPageHeight.Text);
            page.LeftMargin = ConvertUnitsToMillimeters(tbMarginLeft.Text);
            page.TopMargin = ConvertUnitsToMillimeters(tbMarginTop.Text);

            DataBand band = new DataBand();
            band.Parent = page;

            bool fit = true;
            for (int x = 0; x < (int)nudCountColumns.Value; x++)
            {
                for (int y = 0; y < (int)nudCountRows.Value; y++)
                {
                    ShapeObject shape = new ShapeObject();
                    shape.Parent = band;
                    shape.Shape = ShapeKind.RoundRectangle;
                    shape.Border.Color = Color.Gray;
                    shape.Bounds = new RectangleF(x * (widthBands + ConvertUnitsToMillimeters(tbHorizontalPadding.Text)),
                      y * (band1.Bounds.Height + ConvertUnitsToMillimeters(tbVerticalPadding.Text)),
                      widthBands,
                      band1.Bounds.Height);
                    if (shape.Right / Units.Millimeters > page.PaperWidth - page.LeftMargin + 0.1f ||
                      shape.Bottom / Units.Millimeters > page.PaperHeight - page.TopMargin + 0.1f)
                    {
                        (shape.Fill as SolidFill).Color = Color.Red;
                        fit = false;
                    }
                }
            }

            rcSample.Report = sampleReport;
            btnOk.Enabled = fit;
            lbWarning.Visible = !fit;
        } 

        public void InitWizard(Report report)
        {
            this.report = report;
        }

        private float GetWidthBand(BandBase band)
        {
            float widthBand = 0;
            foreach(var item in band.AllObjects)
            {
                if (item is ReportComponentBase)
                    widthBand = Math.Max(widthBand, (item as ReportComponentBase).Right);
            }
            return widthBand;
        }

        public override void Localize()
        {
            base.Localize();
            MyRes res = new MyRes("Forms,CISWizardForm");
            Text = res.Get("");
            gbCIS.Text = res.Get("CIS");
            lbType.Text = res.Get("ProductGroup");
            lbData.Text = res.Get("Data");
            lbTypeBarcodes.Text = res.Get("TypeBarcodes");
            cbLeftMargin.Text = res.Get("LeftMargin");
            lbMethodСirculation.Text = res.Get("MethodСirculation");
            lbCountry.Text = res.Get("Country");
            lbID.Text = res.Get("ID");
            lbSize.Text = res.Get("Size");
            gbPageProps.Text = res.Get("PageProps");
            cbLandscape.Text = res.Get("Landscape");
            lbMarginTop.Text = res.Get("MarginTop");
            lbMarginLeft.Text = res.Get("MarginLeft");
            lbMargin.Text = res.Get("Margins");
            lbPaper.Text = res.Get("Paper");
            lbPageWidth.Text = res.Get("PageWidth");
            lbPageHeight.Text = res.Get("PageHeight");
            lbCountColumns.Text = res.Get("CountColumns");
            lbCountRows.Text = res.Get("CountRows");
            lbHorizontalPadding.Text = res.Get("HorizontalPadding");
            lbVerticalPadding.Text = res.Get("VerticalPadding");
            gbSample.Text = res.Get("Sample");
            btnBorder.Text = res.Get("Border");
            lbWarning.Text = res.Get("Warning");

            cbxType.Items.Clear();
            cbxType.Items.AddRange(
                new object[]
                {
                    res.Get("TransportPack"),
                    res.Get("Pack"),
                    res.Get("Block"),
                    res.Get("Legprom"),
                    res.Get("Perfumes"),
                    res.Get("Footwear"),
                    res.Get("Fur"),
                    res.Get("Photo"),
                    res.Get("Tires"),
                    res.Get("Medicines"),
                    res.Get("Dairy"),
                    res.Get("Water"),
                }
            );
            cbxType.SelectedIndex = 0;

            cbxMethodСirculation.Items.Clear();
            cbxMethodСirculation.Items.AddRange(
                new object[]
                {
                    res.Get("ImportProd"),
                    res.Get("ManufactureProd")
                }
            );
            cbxMethodСirculation.SelectedIndex = 0;
            lbUnitsMarginTop.Text = GetUnits();
            lbUnitsMarginLeft.Text = GetUnits();
            lbUnitsHPadding.Text = GetUnits();
            lbUnitsVPadding.Text = GetUnits();
            lbUnitsPHeight.Text = GetUnits();
            lbUnitsPWidth.Text = GetUnits();
        }

        public CISWizardForm()
        {
            InitializeComponent();
            UpdateDpiDependencies();

            sampleReport = new Report();
            sampleReport.Pages.Add(new ReportPage());
            sampleReport.SmoothGraphics = true;

            // paper
            printerSettings = new PrinterSettings();
            PaperSize defaultPaper = printerSettings.DefaultPageSettings.PaperSize;
            cbxPaper.Items.Add(Res.Get("Forms,PageSetup,Custom"));
            foreach (PaperSize ps in printerSettings.PaperSizes)
            {
                cbxPaper.Items.Add(ps.PaperName);
                if (ps.PaperName == defaultPaper.PaperName)
                    cbxPaper.SelectedIndex = cbxPaper.Items.Count - 1;
            }

            border = new Border();
            update = false;
            Localize();
            CbxType_SelectedIndexChanged(null, null);
        }
    }
}
