// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2024, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using Hiperscan.ApoIdentCommon.ApoConfig;
using Hiperscan.GtkExtensions.Compiler;

namespace Hiperscan.ApoIdentCore.Reporting.LabelPrint
{
    public sealed class LabelPrinterAustriaQM : LabelPrinter
    {
        public LabelPrinterAustriaQM(LabelPrinterSettings settings) : base(settings)
        {

        }

        protected override GraphicsObject CreateLabelGraphics(GraphicsRectangle area, GenericGraphicCompiler compiler)
        {
            this.Compiler = compiler;
            this.CalcSheetPosition(area);
            this.DrawBackground();
            this.CreateMainCanvas(area);

            this.FontSize = 15;
            this.SmallFontSize = 12;
            this.LineWidth = 1;

            double space = 5;
            double y_pos = 0;
            double x_pos = 0;

            double indent1 = 5;
            double indent2 = indent1 + this.MeasureBatchFieldColumn() + space;
            double indent3 = this.LabelWidth - this.MeasurePPNEntryColumn() - indent1 - space - this.MeasurePPNFieldColumn();

            double horizental_line_width = this.LabelWidth - 2 * indent1;
            double logo_width = 60;
            double substancename_width = this.LabelWidth - indent1 - indent2;
            double batch_value_width = indent3 - indent2 - space;

            double testing_space_width = batch_value_width;
            testing_space_width -= this.Compiler.MeasureText(this.LabelInfo.TestId, this.NormalFont).Width;
            testing_space_width -= this.Compiler.MeasureText(this.DateFieldName, this.NormalFont).Width;
            testing_space_width -= this.Compiler.MeasureText(this.LabelInfo.Date, this.NormalFont).Width;
            testing_space_width /= 2;

            double line_feed_after_text = 1.75 * this.FontSize;
            double line_feed_before_text = 0.15 * this.FontSize;
            double text_feed = 1.5 * FontSize;

            //logo
            y_pos = 0;
            x_pos = indent1;
            this.DrawLogo(x_pos + 5, y_pos + 5, logo_width);

            //selected substance name
            y_pos = logo_width - 2 * this.FontSize;
            x_pos = indent2;
            string text = this.LabelInfo.Substance;
            if (String.IsNullOrEmpty(this.LabelInfo.Variety) == false)
                text += ", Sorte: " + this.LabelInfo.Variety;
            this.DrawText(text, x_pos, y_pos, this.NormalFont, substancename_width);

            //line 1
            y_pos = logo_width;
            x_pos = indent1;
            this.DrawHorizentalLine(x_pos, y_pos, horizental_line_width, this.LineWidth);

            //batch field
            y_pos += line_feed_before_text;
            x_pos = indent1;
            this.DrawText(this.BatchFieldName, x_pos, y_pos, this.NormalFont);

            //batch value
            x_pos = indent2;
            this.DrawText(this.LabelInfo.Batch, x_pos, y_pos, this.NormalFont, batch_value_width);

            //ppn field
            x_pos = indent3;
            this.DrawText(this.PPNFieldName, x_pos, y_pos, this.NormalFont);

            //ppn value
            x_pos = this.LabelWidth - indent1 - this.Compiler.MeasureText(this.LabelInfo.PPN, this.NormalFont).Width;
            this.DrawText(this.LabelInfo.PPN, x_pos, y_pos, this.NormalFont);

            //producer field
            y_pos += text_feed;
            x_pos = indent1;
            this.DrawText(this.ProducerFieldName, x_pos, y_pos, this.NormalFont);

            //producer value
            x_pos = indent2;
            this.DrawText(this.LabelInfo.Producer, x_pos, y_pos, this.NormalFont, batch_value_width);

            //reference quantity field
            x_pos = indent3;
            this.DrawText(this.ReferenceQuantityFieldName, x_pos, y_pos, this.NormalFont);

            //reference quantity value
            x_pos = this.LabelWidth - indent1 - this.Compiler.MeasureText(this.LabelInfo.ReferenceQuantity, this.NormalFont).Width;
            this.DrawText(this.LabelInfo.ReferenceQuantity, x_pos, y_pos, this.NormalFont);

            //content field
            y_pos += text_feed;
            x_pos = indent1;
            this.DrawText(this.ContentFieldName, x_pos, y_pos, this.NormalFont);

            //content value
            x_pos = indent2;
            text = "THC: " + this.LabelInfo.THCContent +
                       "   CBD: " + this.LabelInfo.CBDContent;
            this.DrawText(text, x_pos, y_pos, this.NormalFont, this.LabelWidth - x_pos - indent1);

            //line 2
            y_pos += line_feed_after_text;
            x_pos = indent1;
            this.DrawHorizentalLine(x_pos, y_pos, horizental_line_width, this.LineWidth);

            //testing field
            y_pos += line_feed_before_text;
            x_pos = indent1;
            this.DrawText(this.TestIdFieldName, x_pos, y_pos, this.NormalFont);

            //testing id
            x_pos = indent2;
            this.DrawText(this.LabelInfo.TestId, x_pos, y_pos, this.NormalFont);

            //date field
            x_pos = indent3;
            this.DrawText(this.DateFieldName, x_pos, y_pos, this.NormalFont);

            //date value
            x_pos = this.LabelWidth - indent1 - this.Compiler.MeasureText(this.LabelInfo.Date, this.NormalFont).Width;
            this.DrawText(this.LabelInfo.Date, x_pos, y_pos, this.NormalFont);

            //expiry date field
            y_pos += text_feed;
            x_pos = indent1;
            this.DrawText(this.ExpiryDateFieldName, x_pos, y_pos, this.BoldFont);

            //expiry date entry
            x_pos += this.Compiler.MeasureText(this.ExpiryDateFieldName, this.BoldFont).Width + space;
            this.DrawText(this.LabelInfo.ExpiryDate, x_pos, y_pos, this.BoldFont);

            //comment field
            y_pos += text_feed;
            x_pos = indent1;
            this.DrawText(this.CommentFieldName, x_pos, y_pos, this.NormalFont);

            //comment entry
            x_pos += this.Compiler.MeasureText(this.CommentFieldName, this.NormalFont).Width + space;
            this.DrawText(this.LabelInfo.Comment, x_pos, y_pos, this.NormalFont, this.LabelWidth - x_pos - indent1);

            //line 3
            y_pos += line_feed_after_text;
            x_pos = indent1;
            this.DrawHorizentalLine(x_pos, y_pos, horizental_line_width, this.LineWidth);

            //address value
            y_pos += line_feed_before_text;
            x_pos = indent1;
            this.DrawText(this.LabelInfo.Address, x_pos, y_pos, this.SmallFont, this.LabelWidth - indent1);

            return this.VisualRootElement;
        }

        private double MeasureBatchFieldColumn()
        {
            List<string> measure_strings = new List<string>();
            measure_strings.Add(this.BatchFieldName);
            measure_strings.Add(this.ProducerFieldName);
            measure_strings.Add(this.TestIdFieldName);
            measure_strings.Add(this.ContentFieldName);

            return this.MeasureText(measure_strings, this.NormalFont);
        }

        private double MeasurePPNFieldColumn()
        {
            List<string> measure_strings = new List<string>();
            measure_strings.Add(this.PPNFieldName);
            measure_strings.Add(this.ReferenceQuantityFieldName);
            measure_strings.Add(this.DateFieldName);

            return this.MeasureText(measure_strings, this.NormalFont);
        }

        private double MeasurePPNEntryColumn()
        {
            List<string> measure_strings = new List<string>();
            measure_strings.Add(this.LabelInfo.PPN);
            measure_strings.Add(this.LabelInfo.ReferenceQuantity);
            measure_strings.Add(this.LabelInfo.Date);

            return this.MeasureText(measure_strings, this.NormalFont);
        }

        private void DrawLogo(double x_pos, double y_pos, double size)
        {
            string logo_file = Path.GetTempPath();
            logo_file = Path.Combine(logo_file, this.GetType().Name + "_apo_ident__label_printer_logo.png");

            try
            {
                string resource = "Hiperscan.ApoIdentCore.Reporting.LabelPrint.Logo.png";
                using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
                {
                    Bitmap bmp = new Bitmap(stream);
                    bmp.Save(logo_file);
                }

                GraphicsImage image = new GraphicsImage();
                image.FileName = logo_file;
                image.Coordinates.X = x_pos;
                image.Coordinates.Y = y_pos;
                image.Coordinates.Width = size;
                image.Coordinates.Height = size;
                this.MainCanvas.Children.Add(image);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Label printer cannot load logo from file {0}: {1}", logo_file, ex);
            }
        }

        private string BatchFieldName => "Charge:";
        private string ProducerFieldName => "Hersteller:";
        private string PPNFieldName => "PZN:";
        private string ReferenceQuantityFieldName => "Menge:";
        private string ContentFieldName => "Gehalt:";
        private string TestIdFieldName => "Prüfung:";
        private string DateFieldName => "am:";
        private string ExpiryDateFieldName => "Verwendbar bis:";
        private string CommentFieldName => "Bemerkung:";
    }
}
