// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2021 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.IO;
using Gtk;
using Hiperscan.GtkExtensions.Widgets;
using Hiperscan.PdfLib;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Unix;

namespace Hiperscan.Extensions.ApoIdent
{
    public partial class ApoIdentApplication
    {
        private void PrepareProtocolSection()
        {
            this.Control.ProtocolState.UpdateUserField(this.TestUserEntry.IsValid);
            this.Control.ProtocolState.UpdateSupplierField(this.SpecimenSupplierEntry.IsValid);
            this.Control.ProtocolState.UpdateBatchField(this.SpecimenBatchEntry.IsValid);
            this.Control.ProtocolState.UpdateExpiryDateField(this.SpecimenExpiryDateBox.IsValid);

            this.CheckAdditionalTestAsMandatory();

            if (this.Config.LabelPrinterSettings.HasPrinter)
                this.Control.ProtocolState.SetFlag(ProtocolStates.HasLabelPrinter);
            else
                this.Control.ProtocolState.DeleteFlag(ProtocolStates.HasLabelPrinter);
        }

        internal string GetProtocolTestId()
        {
            DateTime date = AppControl.NO_DATE;
            if (this.Control.ProtocolState.HasFlag(ProtocolStates.IdentificationResultExists))
            {
                if (this.SubstanceManagement.CurrentClassification.IsNirMeasurable)
                {
                    if (this.Control.CurrentProcessedSpectrum != null)
                        date = this.Control.CurrentProcessedSpectrum.Timestamp;
                }
                else
                {
                    date = this.Control.NotMeasurableCreationDate;
                }
            }

            string test_id = String.Empty;

            if (date != AppControl.NO_DATE)
                test_id = (date.Year % 100).ToString() + date.ToString("MMdd-HHmmss");


            return test_id;
        }

        private void CreateReport()
        {
            if (string.IsNullOrEmpty(FilesAndDirs.Archive) == true || Directory.Exists(this.Config.Profiles.Current.Archive) == false)
                throw new Exception(Catalog.GetString("Archive directory does not exist or permission is denied."));

            if (Directory.Exists(FilesAndDirs.ArchiveYearDir) == false)
                Directory.CreateDirectory(FilesAndDirs.ArchiveYearDir);

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

            this.RefreshProtocolData();
            this.Control.CurrentReportInfo = new ReportInfo(this); 

            if (old_info != null)
            {
                try { File.Delete(old_info.PdfFileFullName); } catch (Exception) { };
                try { File.Delete(old_info.XmlFileFulleName); } catch (Exception) { };
                if (this.Control.CreateNotMeasurableReport == false)
                    try { File.Delete(old_info.CsvFilFullName); } catch (Exception) { };
            }

            this.Control.CurrentReport = this.SelectReport(this.Control.CurrentReportInfo);

            ReportInfo.Write(this.Control.CurrentReportInfo, FilesAndDirs.ProtocolXmlFileName(this.Control.CurrentReportInfo));
            if (this.Control.CreateNotMeasurableReport == false)
                CSV.Write(this.Control.CurrentProcessedSpectrum, 
                          FilesAndDirs.ProtocolCsvFileName(this.Control.CurrentReportInfo),
                          this.Control.CurrentReportInfo.Culture);

            this.ExchangeDataImportFinishedDialog();
            this.Control.ProtocolState.DeleteFlag(ProtocolStates.ProtocolNotSaved);
        }

        private Report.Generic SelectReport(ReportInfo report_info)
        {
            Report.Generic report = null;

            switch (report_info.ReportCountry)
            {

                case Configurations.ReportCountryType.Austria:
                    report = new Report.Austria(report_info);
                    break;

                case Configurations.ReportCountryType.Germany:
                    report = new Report.Germany(report_info);
                    break;

                case Configurations.ReportCountryType.Switzerland:
                    report = new Report.Switzerland(report_info);
                    break;

                case Configurations.ReportCountryType.GreatBritain:
                    report = new Report.GreatBritain(report_info);
                    break;

                default:
                    throw new NotImplementedException("Unknown report country: " + report_info.ReportCountry);

            }

            return report;
        }

        private void ExchangeDataImportFinishedDialog()
        {
            if (this.SubstanceManagement.ProtocolCompletion == ProtocolAutoCompletionType.ThirdParty)
            {
                try
                {
                    if (this.Config.Profiles.Current.ExchangeData.ExportSuccess == true)
                        return;

                    this.Config.Profiles.Current.ExchangeData.ExportFile(this.Control.CurrentReportInfo);

                    string message = String.Format(Catalog.GetString("The data import for '{0}' is finished. " +
                            "You can still do some changes in the fields 'comment' or 'additional test' " +
                            "before you integrate the protocol in the '{0}'-application."),
                                                   this.Config.Profiles.Current.ExchangeData.ApplicationName);


                    this.Update(ApoIdentApplicationState.ProtocolDataExchangeOk, message);
                }
                catch(Exception ex)
                {
                    string message = String.Format(Catalog.GetString("Cannot finish data import for '{0}': {1}"),
                                                                     this.Config.Profiles.Current.ExchangeData.ApplicationName,
                                                                     ex.Message);

                    this.Update(ApoIdentApplicationState.ProtocolDataExchangeFailed, message, ex);
                                                   
                }
            }
        }


        private bool SaveReport()
        {
            if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolNotSaved) == false)
                return true;

            //TODO Demo version threadSafe
            Preferences.CheckForDemoVersion(this.MainWindow, this.Config);


            string message = String.Empty;
            Exception exception = null;

            try
            {
                this.CreateReport();
            }
            catch (PdfLayoutException ex)
            {
                exception = ex;
                message = String.Format(Catalog.GetString("Error creating file: {0}"), ex.Message);
                message += Catalog.GetString("\n\nThe most common reason for this error is a too long input in the field \"additional test\". " +
                        "Please check this input.");
            }
            catch (Exception ex)
            {
                exception = ex;
                message = String.Format(Catalog.GetString("Error saving file: {0}"), ex.Message);
                message += Catalog.GetString("\n\n" +
                                             "Please check if the archive directory exists and that you can write data in this archive.");

               
            }

            if (exception != null)
            {
                this.Update(ApoIdentApplicationState.ProtocolSavingFailed, message, exception);
                return false;
            }

            this.Update(ApoIdentApplicationState.ProtocolSavingSuccess);
            return true;
        }



        private bool CheckForNotSavedProtocolDetails()
        {
            if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolSectionActive) == false)
                return true;

            if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolNotSaved) == false)
                return true;
                
            this.Update(ApoIdentApplicationState.ProtocolCheckSave);

            bool continue_action = true;

            switch(this.DialogResponse)
            {
                case ResponseType.No:
                    continue_action = true;
                    break;

                case ResponseType.DeleteEvent:
                    continue_action = false;
                    break;

                case ResponseType.Cancel:
                    continue_action = false;
                    break;

                case ResponseType.Yes:
                    continue_action = this.SaveReport();
                    break;

                default:
                    return true;
            }

            if (continue_action)
            {
                this.Control.ProtocolState.DeleteFlag(ProtocolStates.IdentificationResultExists);
                this.IdentServerClient.DiscardResult();  
            }

            return continue_action;
        }

        private void OnSaveReportButtonClicked(object o, EventArgs e)
        {
            lock(this.Control.Transaction)
            {
                this.SaveReport();
            }
        }

        private void OnShowReportButtonClicked(object o, EventArgs e)
        {
            lock (this.Control.Transaction)
            {
                bool success = true;
                if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolNotSaved))
                    success = this.SaveReport();

                if (success == true)
                {
                    try
                    {
                        this.Control.CurrentReport.Show();
                    }
                    catch (Exception ex)
                    {
                        string message = String.Format(Catalog.GetString("Cannot show report: {0}"), ex.Message);
                        this.Update(ApoIdentApplicationState.ProtocolShowingFailed, message);
                    }
                }
            }
        }

        private void OnPrintReportButtonClicked(object o, EventArgs e)
        {
            lock (this.Control.Transaction)
            {
                bool success = true;
                if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolNotSaved))
                    success = this.SaveReport();

                if (success == true)
                {
                    try
                    {
                        this.Control.CurrentReport.Print();
                    }
                    catch (Exception ex)
                    {
                        string message = String.Format(Catalog.GetString("Cannot print report: {0}"), ex.Message);
                        message += Catalog.GetString("\nPlease check the printer setting on your computer.");
                        this.Update(ApoIdentApplicationState.ProtocolPrintingFailed, message);
                    }
                }
            }
        }

        private void OnPrintLabelButtonClicked(object o, EventArgs e)
        {
            lock (this.Control.Transaction)
            {
                bool success = true;
                if (this.Control.ProtocolState.HasFlag(ProtocolStates.ProtocolNotSaved))
                    success = this.SaveReport();

                if (success == true)
                {
                    try
                    {
                        LabelPrinter printer = new LabelPrinter(this.Config.LabelPrinterSettings);
                        printer.Print(this.Control.CurrentReportInfo);
                    }
                    catch (Exception ex)
                    {
                        string message = String.Format(Catalog.GetString("Cannot print label: {0}"), ex.Message);
                        message += Catalog.GetString("\nPlease check the printer settings on your computer " +
                                                     "or check the label printer settings in the preferences dialog.");
                        this.Update(ApoIdentApplicationState.ProtocolLabelPrintingFailed, message);
                    }
                }
            }
        }

        private void RefreshProtocolData()
        {
            this.Control.ReportTestUser = StringHelper.CleanUserInputString(this.test_user_entry.Text); ;
            this.Control.ReportSupplier = StringHelper.CleanUserInputString(this.SpecimenSupplierEntry.GtkEntry.Text);
            this.Control.ReportPpn = StringHelper.CleanUserInputString(this.SpecimenPpnEntry.GtkEntry.Text); ;
            this.Control.ReportWeighingCorr = StringHelper.CleanUserInputString(this.SpecimenWeighingCorrEntry.GtkEntry.Text); ;

            this.Control.ReportBatch = StringHelper.CleanUserInputString(this.SpecimenBatchEntry.GtkEntry.Text);
            this.Control.ReportBatch = StringHelper.ConvertEuroSign(this.Control.ReportBatch);

            this.Control.ReportCommon = StringHelper.CleanUserInputString(this.result_comment_entry.Text);
            this.Control.ReportCommon = StringHelper.ConvertEuroSign(this.Control.ReportCommon);

            this.Control.ReportExpiryDate = this.SpecimenExpiryDateBox.CurrentDate;
            if (this.Control.ReportExpiryDate == OutLinedValidatedMonthYearBox.INVALIDE_DATE)
                throw new Exception(Catalog.GetString("Invalid shelf life date o expiry date."));

            this.Control.ReportAdditionalText = String.Empty; //TODO

            if (this.Config.GuiSettings.UserCompletion.Contains(this.Control.ReportTestUser) == false)
                this.Config.GuiSettings.UserCompletion.Add(this.Control.ReportTestUser);
            this.InitTestUserCompletion();

            if (this.Config.GuiSettings.SupplierCompletion.Contains(this.Control.ReportSupplier) == false)
                this.Config.GuiSettings.SupplierCompletion.Add(this.Control.ReportSupplier);
            this.InitSpecimenSupplierCompletion();
        }
    }
}
