
// 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.Linq;
using System.Collections.Generic;

using Hiperscan.Unix;
using Hiperscan.PdfLib;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.Processing;
using Hiperscan.Spectroscopy.ReferenceChecks;
using Hiperscan.SGS.Benchtop.FinderSetup;
using Hiperscan.Extensions.ReferenceCheck.Control.Acquisition;

namespace Hiperscan.Extensions.ReferenceCheck.Control.Evaluation
{
    public partial class ResultData
    {
        private void ReferenceBlockSetTransflectanceEvaluation()
        {
            this.TransflectanceSessionResults = new List<TransflectanceSessionResults>();

            foreach (var transflectance_session in this.SessionsTransflectance)
            {
                //ReferenceBlockProcessor set = this.NewReferenceBlockProcessorWithCalibrationSpectra(transflectance_session.Id);
                /*FIXME Placeholder for Referenceblock of FindeX
                foreach (var transflectance_spectrum in transflectance_session.Spectra)
                {

                    TransflectanceResult result = this.EvaluateTransflectanceReference(transflectance_spectrum.Value, 
                                                                                       transflectance_session.Id, 
                                                                                       transflectance_spectrum.Key);

                    this.TransflectanceResults.Add(result);
                }
                */
            }
        }

        private void ReferenceWheelSetTransflectanceEvaluation()
        {
            this.TransflectanceSessionResults = new List<TransflectanceSessionResults>();

            foreach (var transflectance_session in this.SessionsTransflectance)
            {
                List<Spectrum> black_spectra = this.BlackSessionResults
                                                   .SelectMany(x => x.BlackResults)
                                                   .Select(x => x.BlackReferenceCheckResult.Spectrum)
                                                   .ToList();
                List<Spectrum> white_spectra = this.WhiteSessionResults
                                                   .SelectMany(x => x.WhiteResults)
                                                   .Select(x => x.StandardWhiteReferenceCheckResult.Spectrum)
                                                   .ToList();
                CalibrationSession calibration = this.CalibrationSessions.First(x => x.Id == transflectance_session.Id);

                TransflectanceSessionResults transflectance_session_result = new TransflectanceSessionResults()
                {
                    SessionNumber = transflectance_session.Id,
                    TransflectanceResults = new List<TransflectanceResult>()
                };

                foreach (var transflectance_spectrum in transflectance_session.Spectra)
                {
                    List<TransflectanceInsertCheckResult> transflectance_session_all_results = new List<TransflectanceInsertCheckResult>();

                    black_spectra.ForEach(black_spectrum => 
                    {
                        white_spectra.ForEach(white_spectrum =>
                        {
                            ReferenceWheelProcessor processor = this.NewReferenceWheelProcessorWithCalibrationSpectras(transflectance_session.Id, (Hiperscan.Spectroscopy.Processing.ReferenceWheelVersion)this.ReferenceWheelVersion);
                            processor.ExternalBlackReference = black_spectrum;
                            processor.ExternalWhiteReference = white_spectrum;
                            processor.ExternalTransflectanceWhiteReference = transflectance_spectrum.Value;
                            processor.InternalDark = calibration.DarkSpectrum;

                            if (processor.ExternalWhiteReference == null |
                                processor.ExternalBlackReference == null |
                                processor.ExternalTransflectanceWhiteReference == null)
                            {
                                throw new Exception(string.Format(Catalog.GetString("Cannot set reference for session ID {0}"), transflectance_session.Id));
                            }

                            ReferenceChecks check = new ReferenceChecks(processor);
                            TransflectanceInsertCheckResult transflectance_result = 
                                check.CheckTransflectanceInsert(processor.ExternalTransflectanceWhiteReference,
                                                                processor.ExternalWhiteReference,
                                                                processor.ExternalWhiteReference.DarkIntensity,
                                                                false);

                            transflectance_session_all_results.Add(transflectance_result);
                        });
                    });

                    transflectance_session_result.TransflectanceResults.Add(new TransflectanceResult()
                    {
                        SerialNumber = transflectance_spectrum.Key,
                        TransflectanceInsertCheckResult = this.GetWorstResult(transflectance_session_all_results)
                    });
                }
                this.TransflectanceSessionResults.Add(transflectance_session_result);
            }
        }

        private TransflectanceInsertCheckResult GetWorstResult(List<TransflectanceInsertCheckResult> transflectance_check_results)
        {
            TransflectanceInsertCheckResult reflectance_mean_min = transflectance_check_results.First();
            TransflectanceInsertCheckResult reflectance_mean_max = transflectance_check_results.First();
            TransflectanceInsertCheckResult reflectance_rms1_max = transflectance_check_results.First();
            TransflectanceInsertCheckResult reflectance_sloap_max = transflectance_check_results.First();
            double rms1_max = transflectance_check_results.First().MaxRms1;
            double slope_max = transflectance_check_results.First().MaxSlope;

            foreach (TransflectanceInsertCheckResult check_result in transflectance_check_results)
            {
                double max_rms1 = Math.Max(rms1_max, check_result.MaxRms1);
                if (max_rms1 >= check_result.MaxRms1)
                {
                    reflectance_rms1_max = check_result;
                    rms1_max = check_result.MaxRms1;
                }

                double max_slope = Math.Max(slope_max, check_result.MaxSlope);
                if (max_slope >= check_result.MaxSlope)
                {
                    reflectance_sloap_max = check_result;
                    slope_max = check_result.MaxSlope;
                }

                double min = Math.Min(reflectance_mean_min.MeanReflectance, check_result.MeanReflectance);
                if (min >= check_result.MeanReflectance)
                {
                    reflectance_mean_min = check_result;
                }

                double max = Math.Max(reflectance_mean_max.MeanReflectance, check_result.MeanReflectance);
                if (max >= check_result.MeanReflectance)
                { 
                    reflectance_mean_max = check_result;
                }
            }

            if (reflectance_mean_max.Spectrum == reflectance_mean_min.Spectrum &&
                reflectance_mean_min.Spectrum == reflectance_rms1_max.Spectrum &&
                reflectance_rms1_max.Spectrum == reflectance_sloap_max.Spectrum)
            {
                return reflectance_mean_max;
            }

            double diff_mean_min = reflectance_mean_min.MeanReflectance - reflectance_mean_min.MinMeanReflectance;
            double diff_mean_max = reflectance_mean_max.MaxMeanReflectance - reflectance_mean_max.MeanReflectance;

            if (diff_mean_min < diff_mean_max)
                return reflectance_mean_min;

            if (diff_mean_min > diff_mean_max)
                return reflectance_mean_max;

            return reflectance_sloap_max;
        }

        internal PdfTableStringCell[,] GetTransflectanceReferenceEvaluationData(int session_id)
        {
            Dictionary<string, TransflectanceInsertCheckResult> results = this.TransflectanceSessionResults
                                                                              .First(x => x.SessionNumber == session_id)
                                                                              .TransflectanceResults
                                                                              .ToDictionary(x => x.SerialNumber, y => y.TransflectanceInsertCheckResult);

            PdfTableStringCell[,] table_data = this.CreateRerferenceTableWithHead(results.Count, 2);

            int index = 1;
            foreach (var item in results)
            {
                table_data[index, 0].Value = item.Key;
                table_data[index, 1].FontType = PDFjet.NET.CoreFont.HELVETICA_BOLD;
                table_data[index, 1].Align = PdfTextAlignments.Center;

                if (item.Value.Success == true)
                {
                    table_data[index, 1].FontColor = PdfColors.DarkGreen;
                    table_data[index, 1].Value = ResultData.PASS;
                }
                else
                {
                    table_data[index, 1].FontColor = PdfColors.Red;
                    table_data[index, 1].Value = ResultData.FAIL;
                }
                /*
                table_data[index, 2].Value = string.Format("{0} > {1} > {2}",
                                                           TransflectanceInsert.REFLECTANCE_MAX,
                                                           item.Value.MeanReflectance.ToString("#0.000"),
                                                           TransflectanceInsert.REFLECTANCE_MIN);
                */
                index++;
            }

            return table_data;
        }
    }
}
