// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2017 Thomas Klose & Torsten Schache, 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.IO;
using System.Diagnostics;
using System.Reflection;
using System.Drawing.Printing;
using System.Text.RegularExpressions;

using Hiperscan.GtkExtensions.Compiler;
using Hiperscan.GtkExtensions.Printing;
using Hiperscan.Unix;
using System.Globalization;
using Hiperscan.Spectroscopy.IdentModule;

namespace Hiperscan.Extensions.ApoIdent
{
    public class LabelPrinter
    {    
        public static readonly string USER_DEFINED_SIZE_NAME = Catalog.GetString("User defined");
        public const double USER_DEFINED_DEFAULT_WIDTH = 50;
        public const double USER_DEFINED_DEFAULT_HEIGHT = 30;

        public LabelPrinter(Configurations.LabelPrinterPreferences settings)
        {
            this.Settings = settings;
        }

        public void PrintTestLabel(Configurations.ProfilePreferences profile)
        {
            ReportInfo info = new ReportInfo();

            Configurations.ReportCountryType report_country = Configurations.ReportCountryType.Germany;
            if (profile != null)
                report_country = profile.ReportCountry;
            info.ReportCountry = report_country;


            ProtocolType protocol_type = ProtocolType.ApoIdent;
            if (profile != null)
                protocol_type = profile.ExchangeData.ProtocolType;
            info.ProtocolType = protocol_type;

            info.Culture = info.GetCulture(report_country);
            info.Company     = Catalog.GetString("Company name");
            info.Street      = Catalog.GetString("Street name and number"); 
            info.Town        = Catalog.GetString("City name and ZIP code");    
            info.Date        = DateTime.Now;
            info.DefaultName = Catalog.GetString("Primary substance name");
            info.LatinName   = Catalog.GetString("Latin substance name");
            info.Batch       = "ABCDEFG-1234567";
            info.CorrectionFactor = (0.999).ToString(info.Culture);
            info.TestId      = "888888888888";
            info.Pzn         = "123456789012345678";
            info.User        = "Lieschen Müller";
            info.Supplier    = "Snake Oil Ltd.";
            info.ExpireDate  = DateTime.Now;
            info.Comment     = Catalog.GetString("Comment");
            info.Serial      = "Serial";
            info.Version     = "Version";
            info.MatchId     = String.Empty;
            info.MatchRating = 0.0;
            info.BAKMarking = BAKMarkingState.Yellow | BAKMarkingState.Blue | BAKMarkingState.Orange;
            info.BAKMrkingActivated = profile.BAKMarkingActivated;

            info.Rating       = 1.0;
            info.MinRating    = 0.98;
            info.IsMatch      = true;
            info.IsMeasurable = true;
            info.Label          = new Label(info, true);

            info.Footer = Catalog.GetString("Created by QuickStep");

            this.Print(info);
        }

        public void Print(ReportInfo info)
        {
            if (this.Settings.HasPrinter == false)
                throw new Exception(Catalog.GetString("Printer settings are not valid."));
                
            this.LableInfo = info;
                
            GraphicsSize page_size = new GraphicsSize()
            {
                Width  = this.Settings.PaperWidthMM,
                Height = this.Settings.PaperHeightMM,
            };
                
            GraphicsPoint page_offset = new GraphicsPoint()
            {
                X = this.Settings.X_IndentMM,
                Y = this.Settings.Y_IndentMM,
            };
                
            int orientation = ((int)this.Settings.Orientation) * 90;
                
            Printing print_job = null;

            string doc_name = "test";
            if (String.IsNullOrEmpty(info.PdfFileFullName) == false)
                doc_name = Path.GetFileNameWithoutExtension(info.PdfFileFullName);
                
            if(EnvironmentInfo.OS == OperatingSystem.Linux)
                print_job = new LinuxPrinting(this.Settings.PrinterName, doc_name, page_size, page_offset, orientation, this.CreateLabelGraphics);
            else
                print_job = new WindowsPrinting(this.Settings.PrinterName, doc_name ,page_size, this.CreateLabelGraphics);    
                
            print_job.PrintData();
        }    
            
        private GraphicsObject CreateLabelGraphics(GraphicsRectangle area, GenericGraphicCompiler compiler)
        {
            ReportInfo info = this.LableInfo;            
                
            double label_width     = 480;
            double label_height = 240;
                
            double offset_x     = this.Settings.X_IndentMM / 25.4 * compiler.ReferenceDpi;
            double offset_y     = this.Settings.Y_IndentMM / 25.4 * compiler.ReferenceDpi;
                
            double scale_factor = this.Settings.Scale;
            double rotate         = 0;
            double translate_x    = 0;
            double translate_y    = 0;
                
            double draw_offset_x = 0.025 * area.Width;
            double draw_offset_y = 0.025 * area.Height;
                
            double draw_width     = 0.95 * area.Width;
            double draw_height     = 0.95 * area.Height;
                
            switch(this.Settings.Orientation)
            {

                case Configurations.PrinterOrientation.Degree_0:
                rotate = 0;
                scale_factor *= Math.Min(draw_width / label_width, draw_height / label_height);
                translate_x = 0;
                translate_y = 0;
                break;
                    
            case Configurations.PrinterOrientation.Degree_90:
                rotate = 90;
                scale_factor *= Math.Min(draw_width / label_height, draw_height / label_width);
                translate_x = 0;
                translate_y = -draw_width;
                break;
                    
            case Configurations.PrinterOrientation.Degree_180:
                rotate = 180;
                scale_factor *= Math.Min(draw_width / label_width, draw_height / label_height);
                translate_x = -draw_width;
                translate_y = -draw_height;
                break;
                    
            case Configurations.PrinterOrientation.Degree_270:
                rotate = 270;
                scale_factor *= Math.Min(draw_width / label_height, draw_height / label_width);
                translate_x = -draw_height;
                translate_y = 0;
                break;
                    
            default:
                break;
                    
            }

            GraphicsGroup visual_tree_root = new GraphicsGroup();
                
            //Debug start
            /*
            GraphicsShapeRectangle background = new GraphicsShapeRectangle(draw_offset_x, draw_offset_y, draw_width, draw_height);
            background.Brush = new GraphicsSolidColorBrush(new GraphicsColor(0,0,1,0.2));
            background.Pen = new GraphicsPen(new GraphicsColor(0,0,1));
            visual_tree_root.Children.Add(background);
                
            GraphicsShapeLine line1 = new GraphicsShapeLine(draw_offset_x,draw_offset_y, draw_width + draw_offset_x, draw_height + draw_offset_y);
            line1.Pen = new GraphicsPen(GraphicsColors.Red, 2);
            visual_tree_root.Children.Add(line1);
                
            GraphicsShapeLine line2 = new GraphicsShapeLine(draw_offset_x, draw_offset_y + draw_height, draw_width + draw_offset_x, draw_offset_y);
            line2.Pen = new GraphicsPen(GraphicsColors.Red, 1);
            visual_tree_root.Children.Add(line2); 
            */        
            //Debug end
                
            //Only for the stupid brother printer

            GraphicsShapeCircle circle = new GraphicsShapeCircle()
            {
                Radius = 0.5,
                X = area.Width / 2,
                Y = area.Height,
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
            };
            visual_tree_root.Children.Add(circle);
                
                
            GraphicsGroup main = new GraphicsGroup();
            //First move to available drawing area
            main.TransformGroup.Add(new GraphicsTranslate(draw_offset_x, draw_offset_y));
            //Second rotate the available drawing area
            main.TransformGroup.Add(new GraphicsRotate(rotate));
            //Third  move available drawing area back in visible range
            main.TransformGroup.Add(new GraphicsTranslate(translate_x, translate_y));
            //Fourth adapt the available drawing area to the given label area
            main.TransformGroup.Add(new GraphicsScale(scale_factor, scale_factor));
            //Fifth move to the userdefined offsets
            main.TransformGroup.Add(new GraphicsTranslate(offset_x / scale_factor, offset_y / scale_factor));
            visual_tree_root.Children.Add(main);
                
            //Debug start
            /*
            GraphicsShapeRectangle label = new GraphicsShapeRectangle(0, 0, label_width, label_height);
            label.Brush = new GraphicsSolidColorBrush(new GraphicsColor(0,1,0,0.2));
            label.Pen = new GraphicsPen(new GraphicsColor(0,1,0, 0.7));
            main.Children.Add(label);
            */
            //Debug end
                

            double x_pos0 = 5;
            double x_pos1 = 170;
            double x_pos2 = 250;
            double x_pos3 = 310;
            double y_pos = this.LableInfo.ReportCountry == Configurations.ReportCountryType.Germany ? 10 : 20;
                
            double font_size = 15;
            double line_factor = 1.2;
            double small_font_factor = 0.9;
            double line_feed = line_factor * font_size;
                
            //Header
            if (info.IsMeasurable == true)
                main.Children.Add(this.DrawLogo(x_pos0 + 40, y_pos, 0.85));
                
            //create fonts
                
            GraphicsFont bold_font = new GraphicsFont()
            {
                FontName = "Helvetica",
                FontSize = font_size,
                FontWeight = GraphicsFontWeights.Bold,
            };
                
            GraphicsFont normal_font = new GraphicsFont()
            {
                FontName =  "Helvetica",
                FontSize = font_size,
                FontWeight = GraphicsFontWeights.Normal,
            };
                
            GraphicsFont small_font = new GraphicsFont()
            {
                FontName =  "Helvetica",
                FontSize = font_size * small_font_factor,
                FontWeight = GraphicsFontWeights.Normal,
            };
                
            GraphicsText text = null;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = bold_font,
                Position = new GraphicsPoint(info.IsMeasurable == true ? x_pos1 -  20 : x_pos0, y_pos + 3),
                Text = info.Label.Header,
            };
            main.Children.Add(text);
                
            GraphicsShapeLine first_line = new GraphicsShapeLine(x_pos0, y_pos + 27,  label_width - 2 * x_pos0 , y_pos + 27);
            first_line.Pen = new GraphicsPen(GraphicsColors.Black, 1);
            main.Children.Add(first_line); 
    
                
            //Body
            y_pos += 30;
            double available_height = label_height - y_pos - 5;
            double available_wdith = label_width - 2 * x_pos0;
            font_size = this.CalcFontsizeVertically(font_size, available_height, line_factor, small_font_factor, compiler);
            font_size = this.CalcFontsizeHorizontally(font_size, available_wdith ,ref x_pos1, ref x_pos2, ref x_pos3, compiler);
            bold_font.FontSize = font_size;
            normal_font.FontSize = font_size;
            small_font.FontSize = font_size * small_font_factor;
            line_feed = font_size * line_factor;
                
                
            //line 1
            line_feed = font_size * line_factor;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = bold_font,
                Text = info.DefaultName,
            };
                
            if(compiler.MeasureText(text).Width > label_width - x_pos1 - x_pos0)
            {
                text.MaxWidth = label_width - 2 * x_pos0;
                text.Position = new GraphicsPoint(x_pos0, y_pos);
                main.Children.Add(text);
            }
            else
            {
                text.Position = new GraphicsPoint(x_pos1, y_pos);
                main.Children.Add(text);
                    
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos0, y_pos),
                    Text = this.LableInfo.Label.Substance,
                };
                main.Children.Add(text);
            }
                
            //line 2
            y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.Identified,
            };
            main.Children.Add(text);
            
            if (info.CustomerResult == true)
            {
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos1, y_pos),
                    Text = this.LableInfo.Label.EvalYes,
                };
                main.Children.Add(text);
            }
            else
            {
                double no_indent = 50;
                GraphicsShapeRectangle yes_rect = new GraphicsShapeRectangle();
                yes_rect.Coordinates.X = x_pos1;
                yes_rect.Coordinates.Y = y_pos + 4;
                yes_rect.Coordinates.Width = normal_font.FontSize;
                yes_rect.Coordinates.Height = normal_font.FontSize;
                yes_rect.Pen = new GraphicsPen(GraphicsColors.Black, 1);
                main.Children.Add(yes_rect);
                
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos1 + normal_font.FontSize * 1.3, y_pos),
                    Text = this.LableInfo.Label.EvalYes,
                };
                main.Children.Add(text);
                
                GraphicsShapeRectangle no_rect = new GraphicsShapeRectangle();
                no_rect.Coordinates.X = x_pos1 + no_indent;
                no_rect.Coordinates.Y = y_pos + 4;
                no_rect.Coordinates.Width = normal_font.FontSize;
                no_rect.Coordinates.Height = normal_font.FontSize;
                no_rect.Pen = new GraphicsPen(GraphicsColors.Black, 1);
                main.Children.Add(no_rect);
                
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos1 + normal_font.FontSize * 1.3 + no_indent, y_pos),
                    Text = this.LableInfo.Label.EvalNo,
                };
                main.Children.Add(text);
                
            }
            
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos2, y_pos),
                Text =  this.LableInfo.Label.Date,
            };
            main.Children.Add(text);
            
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = bold_font,
                Position = new GraphicsPoint(x_pos3, y_pos),
                Text = this.LableInfo.Label.DateContent,
            };
            main.Children.Add(text);    
                
            //line 3
            y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.TestId,
            };
            main.Children.Add(text);
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = info.TestId,
            };
            main.Children.Add(text);
                
            if (String.IsNullOrEmpty(LableInfo.Pzn) == false)
            {
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos2, y_pos),
                    Text =  this.LableInfo.Label.PPN,
                };
                main.Children.Add(text);
                    
                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos3, y_pos),
                    Text = info.Pzn.Replace(" ", String.Empty).Replace("-", String.Empty),
                };
                main.Children.Add(text);
            }
                
                
            //line 4
            y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.UseByDate,
            };
            main.Children.Add(text);
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = this.LableInfo.Label.ExpiryDateContent,
            };
            main.Children.Add(text);


            //line 5
            y_pos += line_feed;

            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text = this.LableInfo.Label.Batch,
            };
            main.Children.Add(text);

            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = info.Batch,
                MaxWidth = label_width - x_pos1 - x_pos0,
            };
            main.Children.Add(text);

                
            //line 6
            y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.CorrectionFactor,
            };
            main.Children.Add(text);
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = info.CorrectionFactor,
            };
            main.Children.Add(text);
                
            //line 7
            y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.Supplier,
            };
            main.Children.Add(text);
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = info.Supplier,
                MaxWidth = label_width - x_pos1 - x_pos0,
            };
            main.Children.Add(text);

            //line BAK Marking optional
            if (this.LableInfo.ReportCountry == Configurations.ReportCountryType.Germany &&
                this.LableInfo.ProtocolType == ProtocolType.ApoIdent &&
                this.LableInfo.BAKMrkingActivated)
            {
                y_pos += line_feed;

                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos0, y_pos),
                    Text = this.LableInfo.Label.BAKMarking,
                };
                main.Children.Add(text);

                text = new GraphicsText()
                {
                    Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                    Font = normal_font,
                    Position = new GraphicsPoint(x_pos1, y_pos),
                    Text = this.GetBakValue(),
                    MaxWidth = label_width - x_pos1 - x_pos0,
                };
                main.Children.Add(text);
        }



        //line 8
        y_pos += line_feed;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                Text =  this.LableInfo.Label.Comment,
            };
            main.Children.Add(text);
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = normal_font,
                Position = new GraphicsPoint(x_pos1, y_pos),
                Text = info.Comment,
                MaxWidth = label_width - x_pos1 - x_pos0,
            };
            main.Children.Add(text);
                
            //Footer
            y_pos += line_feed + 5;
                
            GraphicsShapeLine second_line = new GraphicsShapeLine(x_pos0,  y_pos,  label_width - 2 * x_pos0 , y_pos);
            second_line.Pen = new GraphicsPen(GraphicsColors.Black, 1);
            main.Children.Add(second_line); 
                
            y_pos += 1;
                
            text = new GraphicsText()
            {
                Brush = new GraphicsSolidColorBrush(GraphicsColors.Black),
                Font = small_font,
                Position = new GraphicsPoint(x_pos0, y_pos),
                MaxWidth = label_width - 2 * x_pos0,
            };

            if (String.IsNullOrEmpty(this.LableInfo.Company) || String.IsNullOrEmpty(this.LableInfo.Street) || String.IsNullOrEmpty(this.LableInfo.Town))
                text.Text = String.Empty;
            else
                text.Text = this.LableInfo.Company + ", " + this.LableInfo.Street  + ", " + this.LableInfo.Town;

            main.Children.Add(text);

            return visual_tree_root;
        }
            
        private string GetBakValue()
        {
            string value = String.Empty;
            if (this.LableInfo.BAKMarking == BAKMarkingState.None)
            {
                value = this.LableInfo.Label.NotAvailable;
            }
            else if (this.LableInfo.BAKMarking.HasFlag(BAKMarkingState.Red))
            {
                value = this.LableInfo.Label.BAKRed;
            }
            else
            {
                bool add = false;

                if (this.LableInfo.BAKMarking.HasFlag(BAKMarkingState.Yellow))
                {
                    value += this.LableInfo.Label.BAKYellow;
                    add = true;
                }
                if (this.LableInfo.BAKMarking.HasFlag(BAKMarkingState.Blue))
                {
                    if (add)
                        value += ", ";
                    value += this.LableInfo.Label.BAKBlue;
                    add = true;
                }
                if (this.LableInfo.BAKMarking.HasFlag(BAKMarkingState.Orange))
                {
                    if (add)
                        value += ", ";
                    value += this.LableInfo.Label.BAKOrange;
                    add = true;
                }
            }

            return value;
        }

        private double CalcFontsizeVertically(double font_size, double useable_height, double line_factor, double small_font_factor, GenericGraphicCompiler compiler)
        {
            double calculated_fontsize         = font_size;
            double calculated_height         = 0;
            GraphicsFont small_font = new GraphicsFont()
            {
                FontName = "Helvetica",
                FontSize = font_size * small_font_factor,
                FontWeight = GraphicsFontWeights.Normal,
            };
                
            GraphicsText test_text = new GraphicsText
            {
                Font = small_font,
                Text = "ABCDEFGHIJKLMNOPQRSTUVW",
            };
                
            for(;;)
            {
                small_font.FontSize = small_font_factor * calculated_fontsize;
                calculated_height = compiler.MeasureText(test_text).Height;
                calculated_height += line_factor * calculated_fontsize * small_font_factor;
                calculated_height += 7 * line_factor * calculated_fontsize;
                    
                if(calculated_fontsize < 6 || calculated_height <= useable_height)
                    break;
                    
                calculated_fontsize -= 0.5;
            }
            return calculated_fontsize;
        }
            
        private double CalcFontsizeHorizontally(double font_size, double useable_width, ref double pos1, ref double pos2, ref double pos3, GenericGraphicCompiler compiler)
        {
            double calculated_fontsize         = font_size;
            double calculated_width         = 0;
            GraphicsFont normal_font = new GraphicsFont()
            {
                FontName = "Helvetica",
                FontSize = font_size,
                FontWeight = GraphicsFontWeights.Normal,
            };
                
            GraphicsText test_text1 = new GraphicsText
            {
                Font = normal_font,
                Text = this.LableInfo.Label.Supplier,
            };
                
            GraphicsText test_text2 = new GraphicsText
            {
                Font = normal_font,
                Text = "Nein",
            };
                
            GraphicsText test_text3 = new GraphicsText
            {
                Font = normal_font,
                Text =  this.LableInfo.Label.Batch,
            };
                
            GraphicsText test_text4 = new GraphicsText
            {
                Font = normal_font,
                Text = "888888888888888888",
            };
    
            for(;;)
            {
                 normal_font.FontSize = calculated_fontsize;
                pos1 = compiler.MeasureText(test_text1).Width + 10;
                pos2 = pos1 + compiler.MeasureText(test_text2).Width + 65 + 1.3 * calculated_fontsize;
                pos3 = pos2 + compiler.MeasureText(test_text3).Width + 5;
                calculated_width = pos3 + compiler.MeasureText(test_text4).Width;
                    
                if (calculated_fontsize < 6 || calculated_width <= useable_width)
                    break;
                    
                calculated_fontsize -= 0.5;
            }
            return calculated_fontsize;
        }
            




        private GraphicsGroup DrawLogo(double xoff, double yoff, double scale)
        {
            using (StreamReader reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("ApoIdent.Resources.Others.Label_Apo-Ident.csv")))
            {
                GraphicsGroup group = new GraphicsGroup();
                group.TransformGroup.Add(new GraphicsTranslate(xoff, yoff));
                group.TransformGroup.Add(new GraphicsScale(scale, scale));
                    
                                             
                List<GraphicsPoint> points = new List<GraphicsPoint>();
                    
                Regex regex = new Regex(",");
                System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-US");
                string line;
                    
                while (!string.IsNullOrEmpty(line = reader.ReadLine()))
                {
                    try
                    {
                        string[] s = regex.Split(line);
                        points.Add(new GraphicsPoint(Double.Parse(s[0], culture), -Double.Parse(s[1], culture))); 
                    }
                    catch(Exception)
                    {
                        GraphicsShapePolygone polygone = new GraphicsShapePolygone(points);
                        polygone.Brush = new GraphicsSolidColorBrush(GraphicsColors.Black);
                        polygone.Pen = new GraphicsPen(GraphicsColors.Black);
                        group.Children.Add(polygone);
                        points.Clear();
                    }
                }
                    
                GraphicsShapePolygone last_polygone = new GraphicsShapePolygone(points);
                last_polygone.Brush = new GraphicsSolidColorBrush(GraphicsColors.Black);
                last_polygone.Pen = new GraphicsPen(GraphicsColors.Black);
                group.Children.Add(last_polygone);
                    
                return group;
                }
        }

        public static List<string> PrinterNames
        {
            get
            {
                List<string> printers = new List<string> ();
                try
                {
                    
                    foreach (string name in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
                        printers.Add(name);
                }
                catch(Exception)
                {
                    printers = new List<string> ();
                }

                printers.Sort();
                printers.Insert(0, Catalog.GetString("None"));
                return printers;
            }
        }

        public static Dictionary<string, PaperSize> GetPaperSizes(string printer_name)
        {
            var printer = System.Drawing.Printing.PrinterSettings.InstalledPrinters; //work around for refresh paper names
           
            Dictionary<string, PaperSize> tmp = new Dictionary<string, PaperSize>();

            try 
            {
                PrintDocument pd = new PrintDocument();
                pd.PrinterSettings.PrinterName = printer_name;
                
                foreach (PaperSize paper_size in pd.PrinterSettings.PaperSizes)
                    tmp.Add(paper_size.PaperName, paper_size);
                pd.Dispose();
            }
            catch(Exception)
            {                
            }

            if (tmp.Count == 0)
            {
                PaperSize user_defined = new PaperSize();
                user_defined.PaperName = LabelPrinter.USER_DEFINED_SIZE_NAME;
                user_defined.Width = (int)(LabelPrinter.USER_DEFINED_DEFAULT_WIDTH * 100 / 25.4);
                user_defined.Height = (int)(LabelPrinter.USER_DEFINED_DEFAULT_HEIGHT * 100 / 25.4);
                tmp.Add(user_defined.PaperName, user_defined);
            }

            List<string> paper_sizes = new List<string>(tmp.Keys);
            paper_sizes.Sort();

            Dictionary<string, PaperSize> sorted = new Dictionary<string, PaperSize>();
            foreach (string paper_size in paper_sizes)
                sorted.Add(paper_size, tmp[paper_size]);

            return sorted;
        }

        public static event EventHandler PrinterProcessExited = null;

        public static void StartLabelPrinterSettingsDialog(string printer_name, string paper_name)
        {
            System.Diagnostics.Process control = new System.Diagnostics.Process();

            PlatformID osversion = Environment.OSVersion.Platform;
            if (osversion == PlatformID.Win32NT      ||
                osversion == PlatformID.Win32S       ||
                osversion == PlatformID.Win32Windows ||
                osversion == PlatformID.WinCE)
            {
                // windows
                control.StartInfo.FileName = "rundll32.exe";
                control.StartInfo.Arguments = "printui.dll,PrintUIEntry /e /n\"" + printer_name + "\"";
            }
            else
            {
                // linux
                control.StartInfo.FileName  = "system-config-printer";
                    //                    control.StartInfo.Arguments = "--configure-printer=\"" + this.label_printer_combo.ActiveText + "\"";
            }

            string[] parameters = new string[] { printer_name, paper_name };

            control.StartInfo.CreateNoWindow  = false;
            control.StartInfo.UseShellExecute = false;
            control.StartInfo.RedirectStandardOutput = false;
            control.EnableRaisingEvents = true;
            control.Exited += (sender, e) => 
            {
                if (LabelPrinter.PrinterProcessExited != null)
                    LabelPrinter.PrinterProcessExited(parameters, EventArgs.Empty);
            };

            control.Start();    
        }
            
        private  ReportInfo LableInfo    {get;set;}
        private Configurations.LabelPrinterPreferences Settings {get; set;}
    }
}

