// 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.Globalization;
using System.IO;

using Hiperscan.PdfLib;
using Hiperscan.PdfPrint;
using Hiperscan.Spectroscopy.IdentModule;
using Hiperscan.Unix;


namespace Hiperscan.Extensions.ApoIdent.Report
{
    public abstract class Generic
    {
        public const double DEFAULT_TAB_INDENT = 130;
        public const double DEFAULT_FONT_SIZE = 10;
        public const double DEFAULT_LINE_DISTANCE = 1.5;
        public const double DEFAULT_RIGHT_MARGIN = 60;
        public const double DEFAULT_LOWER_MARGIN = 60;
        public const double DEFAULT_FEED = 10;

        public Generic(ReportInfo report_info)
        {
            Console.WriteLine("Creating report...");

            this.ReportInfo = report_info;
            this.Layout = null;

            this.NumberOfAdditionalTextLines = this.ReportInfo.IsMeasurable ? 3 : 15;
            this.Text = String.Empty;

            this.State = new PdfCreationState();
            this.SetDefaultValues();

            for (; ; )
            {
                try
                {
                    if (this.State.IsSet(PdfCreationStates.TryMode) == true &&
                        this.State.IsSet(PdfCreationStates.Init) == false)
                    {
                        if (this.ReferenceFontSize < 7.9)
                        {
                            if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == false)
                            {
                                this.State.Set(PdfCreationStates.CreateTwoSides, true);
                                this.SetDefaultValues();
                            }
                            else if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == true)
                            {
                                this.Delete();
                                throw new PdfLayoutException(Catalog.GetString("There is not enough space for creating protocol."));
                            }
                        }
                        else
                        {
                            double scale = (this.ReferenceFontSize - 0.5) / this.ReferenceFontSize;
                            this.ReferenceFontSize *= scale;
                            this.ReferenceLineDistance *= scale;
                            this.ReferenceTabIndent *= scale;
                            this.ReferenceParagraphFeed *= scale;
                        }
                    }

                    if (this.CreatePageOne() == true)
                    {
                        if (this.State.IsSet(PdfCreationStates.CreateTwoSides) == false)
                        {
                            if (this.State.IsSet(PdfCreationStates.TryMode) == false)
                            {
                                break;
                            }
                            else
                            {
                                this.State.Set(PdfCreationStates.TryMode, false);
                                continue;
                            }
                        }
                    }
                    else
                    {
                        continue;
                    }

                    if (this.CreatePageTwo() == true)
                    {
                        if (this.State.IsSet(PdfCreationStates.TryMode) == false)
                        {
                            break;
                        }
                        else
                        {
                            this.State.Set(PdfCreationStates.TryMode, false);
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
                catch (Exception ex)
                {
                    this.Delete();
                    throw ex;
                }
            }

            try
            {
                this.CreateFirstValidationPage();
            }
            catch (Exception ex)
            {
                this.Delete();
                throw ex;
            }

            this.Layout.Save();
            Console.WriteLine("Done.");
        }

        private void SetDefaultValues()
        {
            this.ReferenceTabIndent = Generic.DEFAULT_TAB_INDENT;
            this.ReferenceFontSize = Generic.DEFAULT_FONT_SIZE;
            this.ReferenceLineDistance = Generic.DEFAULT_LINE_DISTANCE;
            this.ReferenceParagraphFeed = Generic.DEFAULT_FEED;
        }

        protected virtual bool CreatePageOne()
        {
            if (this.State.IsSet(PdfCreationStates.Init) == true)
            {
                this.Layout = new Layout(PdfPageSizes.A4_PORTRAIT, this.ReportInfo.PdfFileFullName);
                this.Layout.PDF.SetAuthor(this.ReportInfo.Company);
                this.Layout.PDF.SetTitle(this.ReportInfo.Label.Header);
                this.Layout.PDF.SetSubject(this.ReportInfo.Label.Header);
                this.State.Set(PdfCreationStates.Init, false);
            }

            this.State.CurrentPage = 1;

            this.Layout.SimulateDrawing = this.State.IsSet(PdfCreationStates.TryMode) == true;
            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;
            this.Layout.RightMargin = Generic.DEFAULT_RIGHT_MARGIN;
            this.Layout.LowerMargin = Generic.DEFAULT_LOWER_MARGIN;
            this.Layout.LineDistance = this.ReferenceLineDistance;

            this.CreateHeader();
            if (this.CreateAddressHeader() == false)
                return false;

            if (this.CreateSubstanceProperties() == false)
                return false;

            if (this.CreateNirProperties() == false)
                return false;

            if (this.CreateCommentProperties() == false)
                return false;

            if (this.CreateGraphics() == false)
                return false;

            if (this.CreateNirResultSection() == false)
                return false;

            if (this.CreateAdditionalTest() == false)
                return false;

            if (this.CreateFinalResult() == false)
                return false;

            if (this.CreateTestCertificateSection() == false)
                return false;

            if (this.CreateSignature() == false)
                return false;

            this.CreateFooter();


            return true;
        }

        protected virtual bool CreatePageTwo()
        {
            this.Layout.AddNewPage();

            this.State.CurrentPage = 2;

            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;

            this.CreateHeader();
            if (this.CreateAddressHeader() == false)
                return false;

            if (this.CreateSubstanceProperties() == false)
                return false;

            if (this.CreateAdditionalTest() == false)
                return false;

            if (this.CreateFinalResult() == false)
                return false;

            if (this.CreateTestCertificateSection() == false)
                return false;

            this.CreateFooter();
            return true;
        }

        protected void CreateFirstValidationPage()
        {
            if (this is GreatBritain)
                return;

            if (this.ReportInfo.ClassificationType == ClassificationType.NonMultiple)
                return;

            if (this.ReportInfo.ValidationReportInfo == null)
                return;

            this.Layout.AddNewPage();

            this.State.CurrentPage++;

            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;

            this.CreateValidationHeader();
            this.CreateValidationTableResult();
            this.CreateValidationTestResult();
            this.CreateValidationDistanceTable();
            this.CreateValidationDemarcationTable();

            this.CreateFooter();
        }

        protected void AppendValidationPage(int index)
        {
            this.Layout.AddNewPage();

            this.State.CurrentPage++;

            this.Layout.YPosition = 0;
            this.Layout.XPosition = 0;

            this.CreateValidationHeader();
            this.CreateValidationDemarcationTable(index);

            this.CreateFooter();
        }

        protected abstract void CreateHeader();
        protected abstract bool CreateAddressHeader();
        protected abstract bool CreateSubstanceProperties();
        protected abstract bool CreateNirProperties();
        protected abstract bool CreateCommentProperties();
        protected abstract bool CreateGraphics();
        protected abstract bool CreateNirResultSection();
        protected abstract bool CreateSingleNegativeResult();
        protected abstract bool CreateSinglePositiveResult();
        protected abstract bool CreateMultipleNegativeResult();
        protected abstract bool CreateMultiplePositiveResult();
        protected abstract bool CreateNonMultipleNegativeResult();
        protected abstract bool CreateNonMultiplePositiveResult();
        protected abstract bool AddNirEvaluation();
        protected abstract bool CreateAdditionalTest();
        protected abstract bool CreateFinalResult();
        protected abstract bool CreateTestCertificateSection();
        protected abstract bool CreateSignature();
        protected abstract void CreateFooter();

        protected abstract void CreateValidationHeader();
        protected abstract void CreateValidationTableResult();
        protected abstract void CreateValidationTestResult();
        protected abstract void CreateValidationDistanceTable();
        protected abstract void CreateValidationDemarcationTable(int index = 0);

        public static void Print(string file)
        {
            PdfPrinting.Print(file);
        }

        protected string GetSubstanceName()
        {
            return BatchExtension.RemoveExtension(this.ReportInfo.DefaultName);
        }

        protected string GetLatinName()
        {
            return BatchExtension.RemoveExtension(this.ReportInfo.LatinName);
        }

        public void Show()
        {
            if (!string.IsNullOrEmpty(this.ReportInfo.PdfFileFullName))
            {
                FileInfo file = new System.IO.FileInfo(this.ReportInfo.PdfFileFullName);

                if (file.Exists)
                {
                    Process.OpenUri(this.ReportInfo.PdfFileFullName);
                    return;
                }
            }

            throw new Exception(Catalog.GetString("No report available."));
        }

        public void Print()
        {
            Generic.Print(this.ReportInfo.PdfFileFullName);
        }

        private void Delete()
        {
            try
            {
                this.Layout.Save();
                File.Delete(this.ReportInfo.PdfFileFullName);
            }
            catch (Exception)
            {
            }
        }

        protected abstract CultureInfo Culture { get; set; }

        protected PdfCreationState State { get; set; }
        protected Layout Layout { get; set; }
        protected double ReferenceTabIndent { get; set; }
        protected double ReferenceFontSize { get; set; }
        protected double ReferenceLineDistance { get; set; }
        protected double ReferenceParagraphFeed { get; set; }
        protected string Text { get; set; }

        protected ReportInfo ReportInfo { get; set; }
        protected int NumberOfAdditionalTextLines { get; set; }
        protected abstract string SubstanceTestType { get; }

        protected int NumberOfA_Batches { get; set; } = 0;
        protected int NumberOfB_Batches { get; set; } = 0;
        protected int NumberOfC_Batches { get; set; } = 0;

        protected PdfTable Table { get; set; }
        protected PdfTableStringCell[,] TableCells {get; set;}
        protected double TableBorderWidth { get; set; } = 0.5;
        protected double TableFirstColumnWidth { get; set; } = 0;
        protected double TableTopCellPadding { get; set; } = 2;
        protected double TableBottomCellPadding { get; set; } = 4;
        protected double[] TableColumnWidths { get; set; }
        protected int TableNumberOfColumns { get; set; }
    }
}

