// 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.IO;
using Hiperscan.AnalysisModule;
using Hiperscan.ApoIdentCore.Reporting.Protocol.Validation;
using Hiperscan.ApoIdentCore.Reporting.ReportData;
using Hiperscan.Common.I18n;
using Hiperscan.ApoIdentCommon.ApoConfig.Enums;
using Hiperscan.PdfLib;
using Hiperscan.PdfPrint;
using Hiperscan.Unix;

namespace Hiperscan.ApoIdentCore.Reporting.Protocol
{
    public partial class GenericProtocol
    {
        public GenericProtocol(ReportInfo info)
        {
            Console.WriteLine("Creating report...");

            this.Args = new PdfArgs();
            this.Args.Info = info;
            this.Args.State = new PdfCreationState();
            this.SetDefaultValues();

            for (; ; )
            {
                try
                {
                    bool page_success = false;
                    if (this.Args.State.IsSet(PdfCreationStates.CreateTwoPages) == false)
                    {
                        page_success = this.CreatePageOne();
                    }
                    else
                    {
                        page_success = this.CreatePageOne();
                        if (page_success)
                            page_success = this.CreatePageTwo();
                    }

                    if (page_success)
                    {
                        this.CreateFirstValidationPage();

                        if (this.Args.State.IsSet(PdfCreationStates.TryMode))
                        {
                            this.Args.State.Set(PdfCreationStates.TryMode, false);
                            continue;
                        }
                        else
                        {
                            this.Args.Layout.Save();
                            Console.WriteLine("Done.");
                            break;
                        }
                    }

                    if (this.Args.ReferenceFontSize < 7.9)
                    {
                        if (this.Args.State.IsSet(PdfCreationStates.CreateTwoPages) == false)
                        {
                            this.Args.State.Set(PdfCreationStates.CreateTwoPages, true);
                            this.SetDefaultValues();
                        }
                        else if (this.Args.State.IsSet(PdfCreationStates.CreateTwoPages) == true)
                        {
                            this.Delete();
                            throw new PdfLayoutException(Catalog.GetString("Cannot create report: Not enough disk space."));
                        }
                    }
                    else
                    {
                        double scale = (this.Args.ReferenceFontSize - 0.5) / this.Args.ReferenceFontSize;
                        this.Args.ReferenceFontSize *= scale;
                        this.Args.ReferenceLineDistance *= scale;
                        this.Args.ReferenceTabIndent *= scale;
                        this.Args.ReferenceParagraphFeed *= scale;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error while creatng report: {0}", ex);
                    this.Delete();
                    throw;
                }
            }
        }

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

        private bool CreatePageOne()
        {
            if (this.Args.State.IsSet(PdfCreationStates.Init) == true)
            {
                this.Args.Layout = new Layout(PdfPageSizes.A4_PORTRAIT, this.Args.Info.PdfFileFullName);
                this.Args.Layout.PDF.SetAuthor(this.Args.Info.Company);
                this.Args.Layout.PDF.SetTitle(Catalog.GetString("Measurement report"));
                this.Args.Layout.PDF.SetSubject(Catalog.GetString("Measurement report"));
                this.Args.State.Set(PdfCreationStates.Init, false);
            }

            this.Args.State.CurrentPage = 1;

            if (this.Args.State.IsSet(PdfCreationStates.TryMode) == true)
                this.Args.State.TotalPages = 1;

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

            IList<IDraw> drawings = this.GetPageOneDrawings();
            foreach (IDraw drawer in drawings)
            {
                if (drawer.Draw(this.Args) == false)
                    return false;
            }

            return true; 
        }

        private bool CreatePageTwo()
        {
            this.Args.Layout.AddNewPage();
            this.Args.State.CurrentPage = 2;
            this.Args.Layout.YPosition = 0;
            this.Args.Layout.XPosition = 0;

            if (this.Args.State.IsSet(PdfCreationStates.TryMode) == true)
                this.Args.State.TotalPages = 2;

            IList<IDraw> drawings = this.GetPageTwoDrawings();
            foreach (IDraw drawer in drawings)
            {
                if (drawer.Draw(this.Args) == false)
                    return false;
            }

            return true;
        }

        private void CreateFirstValidationPage()
        {
            bool print_validation = this.Args.Info.ReportCountry == ReportCountryTypes.Germany ||
                               this.Args.Info.ReportCountry == ReportCountryTypes.Austria ||
                               this.Args.Info.ReportCountry == ReportCountryTypes.Switzerland;

            if (print_validation == false)
                return;

            if (this.Args.Info.AnalysisType == AnalysisType.Quantification)
                return;

            if (this.Args.Info.ValidationReportInfo == null)
                return;

            this.Args.Layout.AddNewPage();
            this.Args.State.CurrentPage++;
            this.Args.Layout.YPosition = 0;
            this.Args.Layout.XPosition = 0;

            if (this.Args.State.IsSet(PdfCreationStates.TryMode) == true)
                this.Args.State.TotalPages++;

            DeValidation validation_report = new DeValidation(this.Args);
            validation_report.Draw();
        }

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

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

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

        public void Print()
        {
            PdfPrinting.Print(this.Args.Info.PdfFileFullName);
        }

        private void Delete()
        {
            try
            {
                this.Args.Layout.Save();
                FileIO.DeleteFile(this.Args.Info.PdfFileFullName);
            }
            catch (Exception) { }
        }

        protected PdfArgs Args { get; set; }
    }
}
