// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2022, 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 Hiperscan.PdfLib;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Unix;
using Hiperscan.ApoIdentCore.Reporting.ReportData;
using Hiperscan.ApoIdentCore.SectionManager.Substance.SubstanceSelection;
using Hiperscan.ApoIdentCore.GuiControl;
using Hiperscan.ApoIdentCore.Reporting.LabelPrint;
using Hiperscan.ApoIdentCommon.ApoConfig;
using Hiperscan.GuiExtensions.Dialog;
using Hiperscan.ApoIdentCore.Reporting.Protocol;
using Hiperscan.AnalysisModule;

namespace Hiperscan.ApoIdentCore.SectionManager.Protocol
{
    public class ProtocolManager : ISectionManager
    {
        public event EventHandler DemoVersionDetected = null;
        public event EventHandler DataExchangeSaved = null;
        public event EventHandler ProtocolSaved = null;
        public event EventHandler DataExchangeSuccessStateChanged = null;
        public ApoUpdateHandler SaveResponseNeeded = null;

        public ProtocolManager(ProfileManager profile_manager, LabelPrinterSettings settings)
        {
            this.ProfileManager = profile_manager;
            this.PrinterSettings = settings;
        }

        public bool CheckProtocolSaveState(AppControl control)
        {
            if (this.AreSpecimenDataComplete == false)
                return true;

            if (this.AreResultDataComplete == false)
                return true;

            if (this.ArePharmacyDataComplete == false)
                return true;

            if (this.IsProtocolSaved)
                return true;

            UpdateArgs args = new UpdateArgs();
            args.DialogArgs.StandardDialogType = StandardDialogType.RemindSaving;
            args.DialogArgs.Message = Catalog.GetString(@"Last changes to the report have not been saved yet.
Do you want to save them now?");
            args.DialogArgs.Title = Catalog.GetString("Note about saving");

            this.SaveResponseNeeded?.Invoke(args);

            if (args.DialogArgs.Response == DialogRespnseType.None)
                return true;

            bool continue_action = true;

            switch (args.DialogArgs.Response)
            {
                case DialogRespnseType.No:
                    continue_action = true;
                    break;

                case DialogRespnseType.DeleteEvent:
                    continue_action = false;
                    break;

                case DialogRespnseType.Cancel:
                    continue_action = false;
                    break;

                case DialogRespnseType.Yes:
                    continue_action = this.SaveProtocol(control, true);
                    break;

                default:
                    return true;
            }

            return continue_action;
        }

        private void CreateReport(AppControl control)
        {
            ProfileSettings profile = this.ProfileManager.CurrentProfile;

            if (string.IsNullOrEmpty(profile.Archive) || false == FileIO.ExistsDirectory(profile.Archive))
                throw new Exception(Catalog.GetString("Archive directory does not exist or permission is denied."));

            FileIO.CreateDirectory(profile.ArchiveYearDir);

            ReportInfo old_info = null;
            if (this.CurrentReport != null)
                old_info = this.CurrentReportInfo;

            this.CurrentReportInfo = new ReportInfo(control);

            if (old_info != null)
            {
                FileIO.DeleteFile(old_info.PdfFileFullName, true);
                FileIO.DeleteFile(old_info.XmlFileFulleName, true);
                if (this.SubstancesCatalog.IsSelectedSubstanceNirMeasurable)
                    FileIO.DeleteFile(old_info.CsvFilFullName, true);
            }

            this.CurrentReport = new GenericProtocol(this.CurrentReportInfo);
            ReportInfo.Write(this.CurrentReportInfo, this.CurrentReportInfo.ProtocolXmlFileName(this.ProfileManager));
            if (this.SubstancesCatalog.IsSelectedSubstanceNirMeasurable)
                CSV.Write(this.CurrentReportInfo.Spectrum,
                          this.CurrentReportInfo.ProtocolCsvFileName(this.ProfileManager));

            this.ProfileManager.CurrentProfile.SaveCacheData();
            this.IsProtocolSaved = true;
        }

        public bool SaveProtocol(AppControl control, bool is_last_chance = false)
        {
            if (this.IsProtocolSaved)
                return true;

            if (this.ProfileManager.IsDemoVersion)
                this.DemoVersionDetected?.Invoke(this, EventArgs.Empty);

            this.SaveSuccess = false;

            try
            {
                this.CreateReport(control);
                this.SaveSuccess = true;
            }
            catch (PdfLayoutException ex)
            {
                this.Exception = ex;
                this.ErrorTitle = Catalog.GetString("Error saving protocol");
                this.ErrorMessage = String.Format(Catalog.GetString("Error while creating file: {0}"), ex.Message);
                this.ErrorMessage += Catalog.GetString(@"

The most common reason for this error is a too extensive text the field ""Additional Tests"". Please check the input.");
            }
            catch (Exception ex)
            {
                this.Exception = ex;
                this.ErrorTitle = Catalog.GetString("Error saving protocol");
                this.ErrorMessage = String.Format(Catalog.GetString("Error while saving file: {0}"), ex.Message);
                this.ErrorMessage += Catalog.GetString(@"

Please check if the archive directory exists and that you have write access to it. Another cause for this problem might be an open measuring protocol.");
            }

            this.ProtocolSaved?.Invoke(this, EventArgs.Empty);

            if (this.SaveSuccess)
                this.SaveSuccess = this.FininishDataExchange(control.ResultManager.GetTypeOfAdditionalTest(), is_last_chance);

            return this.SaveSuccess;
        }

        private bool FininishDataExchange(string type_of_additional_test, bool is_last_chance)
        {
            if (this.SubstancesCatalog.SelectionType == SubstanceSelectionType.ThirdParty)
            {
                try
                {
                    if (this.DataExchangeSuccess == true)
                        return true;

                    this.ProfileManager.CurrentProfile.ExchangeData.ExportFile(this.CurrentReportInfo.PdfFileFullName);

                    if (is_last_chance == false)
                    {
                        if (this.SubstancesCatalog.AnalysisType != AnalysisType.Quantification)
                        {
                            this.DataExchangeMessage = String.Format(Catalog.GetString("The data import for '{0}' is successfully finished. You can still do some changes in the fields 'comment' or '{1}' before you integrate the report in the '{0}'-application."),
                                                           this.ProfileManager.CurrentProfile.ExchangeData.ApplicationName,
                                                           type_of_additional_test);
                        }
                        else
                        {
                            this.DataExchangeMessage = String.Format(Catalog.GetString("The data import for '{0}' is successfully finished. You can still do some changes in the field 'comment'."),
                                                               this.ProfileManager.CurrentProfile.ExchangeData.ApplicationName);
                        }
                    }
                    else
                    {
                        this.DataExchangeMessage = String.Format(Catalog.GetString("The data import for '{0}' is successfully finished and you may now integrate the report in the '{0}'-application."),
                                                       this.ProfileManager.CurrentProfile.ExchangeData.ApplicationName);
                    }
                    this.DataExchangeSuccess = true;
                }
                catch (Exception ex)
                {
                    this.Exception = ex;
                    this.ErrorTitle = Catalog.GetString("Error exchanging data");
                    this.ErrorMessage = String.Format(Catalog.GetString("Cannot finish data import for '{0}': {1}"),
                                                                     this.ProfileManager.CurrentProfile.ExchangeData.ApplicationName,
                                                                     ex.Message);
                }

                    
                this.DataExchangeSaved?.Invoke(this, EventArgs.Empty);

                return this.DataExchangeSuccess;
            }

            return true;
        }

        public bool ShowProtocol()
        {
            try
            {
                this.CurrentReport.Show();
                return true;
            }
            catch(Exception ex)
            {
                this.Exception = ex;
                this.ErrorTitle = Catalog.GetString("Error showing protocol");
                this.ErrorMessage = String.Format(Catalog.GetString("Cannot show report: {0}"), ex.Message);
                return false;
            }
        }

        public bool PrintProtocol()
        {
            try
            {
                this.CurrentReport.Print();
                return true;
            }
            catch (Exception ex)
            {
                this.Exception = ex;
                this.ErrorTitle = Catalog.GetString("Error printing protocol");
                this.ErrorMessage = String.Format(Catalog.GetString("Cannot print report: {0}"), ex.Message);
                this.ErrorMessage += Catalog.GetString(@"
Please check the printer settings on your computer.");
                return false;
            }
        }

        public bool LabelPrint()
        {
            try
            {
                LabelPrinter.Print(this.PrinterSettings, this.CurrentReportInfo);
                return true;
            }
            catch (Exception ex)
            {
                this.Exception = ex;
                this.ErrorTitle = Catalog.GetString("Error printing protocol");
                this.ErrorMessage = String.Format(Catalog.GetString("Cannot print label: {0}"), ex.Message);
                this.ErrorMessage += Catalog.GetString(@"
Please check the printer settings on your computer and in the Apo-Ident preferences dialogue.");
                return false;
            }
        }

        public void UpdateAfterSubstanceSelection(SubstancesCatalog substances_catalog)
        {
            this.SubstancesCatalog = substances_catalog;
        }

        public void Clear()
        {
            this.Reset();
        }

        public void Reset()
        {
            this.SaveSuccess = false;
            this.DataExchangeSuccess = false;
            this.SubstancesCatalog = null;
            this.DiscardReport();
        }

        public void DiscardReport()
        {
            this.CurrentReport = null;
            this.IsProtocolSaved = false;
            this.CurrentReport = null;
            this.CurrentReportInfo = null;
        }

        public bool IsComplete
        {
            get
            {
                return this.SubstancesCatalog != null &&
                    this.AreResultDataComplete == true && 
                           this.AreSpecimenDataComplete &&
                           this.ArePharmacyDataComplete;
            }
        }

        private bool data_exchanged_success = true;
        public bool DataExchangeSuccess
        {
            get
            {
                return this.data_exchanged_success;
            }

            set
            {
                if (this.data_exchanged_success == value)
                    return;

                this.data_exchanged_success = value;
                this.DataExchangeSuccessStateChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        public DialogRespnseType SaveResponse { get; set; }

        public bool AreSpecimenDataComplete { get; set; } = false;
        public bool AreResultDataComplete { get; set; } = false;
        public bool ArePharmacyDataComplete { get; set; } = false;
        public bool IsProtocolSaved { get; set; } = false;
        public LabelPrinterSettings PrinterSettings { get; private set; }

        private ProfileManager ProfileManager { get; set; }
        private SubstancesCatalog SubstancesCatalog { get; set; }

        private GenericProtocol CurrentReport { get; set; } = null;
        private ReportInfo CurrentReportInfo { get; set; } = null;

        public Exception Exception { get; private set; } = null;
        public string ErrorMessage { get; private set; } = String.Empty;
        public string ErrorTitle { get; private set; } = String.Empty;

        public string DataExchangeMessage { get; private set; }
        public bool SaveSuccess { get; set; }
    }
}
