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

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

namespace Hiperscan.Extensions.ReferenceCheck.Control.Evaluation
{
    public partial class ResultData
    {
        [XmlIgnore]
        public const double MAX_BLACK_REFERENCE_REFLECTANCE_LIMIT = 0.09d;// 0.03d In QualityAssurance
        [XmlIgnore]
        public const double MIN_REFLECTANCE_FOR_LINEAR_REGRESSION = 1050.0;
        [XmlIgnore]
        public const double MAX_REFLECTANCE_FOR_LINEAR_REGRESSION = 1850.0;

        private void ReferenceBlockSetBlackEvaluation()
        {
            this.BlackSessionResults = new List<BlackSessionResults>();

            foreach (var black_session in this.SessionsBlack)
            {
                /*FIXME Placeholder for Referenceblock of FindeX
                ReferenceBlockSet set = new ReferenceBlockSet(this.Creator);
                AcquisitionSession empty_session = this.SessionsEmpty.First(x => x.Id == black_session.Id);
                CalibrationSession calibration = this.CalibrationSessions.First(x => x.Id == black_session.Id);

                set.DarkReference = calibration.DarkSpectrum;
                set.FixTwoGlassOxideReference = calibration.OxidSpectrum;
                set.FixTwoGlassWhiteReference = calibration.WhiteSpectrum;

                foreach (var black_spectrum in black_session.Spectra)
                {
                    set.FixTwoGlassBlackReference = black_spectrum.Value;

                    BlackResult result = this.EvaluateBlackReference(set.FixTwoGlassBlackReference, 
                                                                     black_session.Id, 
                                                                     black_spectrum.Key);
                    this.BlackResults.Add(result);
                }
                    */
            }
        }

        private void ReferenceWheelSetBlackEvaluation()
        {
            this.BlackSessionResults = new List<BlackSessionResults>();

            foreach (var black_session in this.SessionsBlack)
            {
                AcquisitionSession white_session = this.SessionsWhite
                                                       .First(x => x.Id == black_session.Id);
                AcquisitionSession empty_session = this.SessionsEmpty
                                                       .First(x => x.Id == black_session.Id);

                BlackSessionResults black_session_results = new BlackSessionResults()
                {
                    SessionNumber = black_session.Id,
                    BlackResults = new List<BlackResult>()
                };

                foreach (var black_spectrum in black_session.Spectra)
                {
                    ReferenceWheelProcessor processor = 
                        this.NewReferenceWheelProcessorWithCalibrationSpectras(black_session.Id, (Hiperscan.Spectroscopy.Processing.ReferenceWheelVersion)this.ReferenceWheelVersion);
                    processor.ExternalWhiteReference = white_session.Spectra.First().Value;
                    processor.ExternalBlackReference = empty_session.Spectra.First().Value;

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

                    Spectrum processed = processor.Process(black_spectrum.Value);
                    ReferenceChecks reference_checks = new ReferenceChecks(processor);
                    BlackReferenceCheckResult check_result = reference_checks.CheckBlackReference(processed, false);

                    processed.LimitBandwidth = true;
                    DataSet reflectance = processed.Intensity / processed.Reference.Intensity;

                    List<int> indices = reflectance.Find('x', '<', ResultData.MIN_REFLECTANCE_FOR_LINEAR_REGRESSION);
                    reflectance.RemoveAt(indices);
                    indices = reflectance.Find('x', '>', ResultData.MAX_REFLECTANCE_FOR_LINEAR_REGRESSION);
                    reflectance.RemoveAt(indices);

                    DataSet ds = reflectance.LinearRegressionCurve();
                    Console.WriteLine("Spectrum evaluation: Max(R) = {0}, Min(R) = {1}, LinReg_Max(R) = {2}, LinReg_Min(R) = {3}",
                                      reflectance.YMax(), reflectance.YMin(), ds.YMax(), ds.YMin());

                    bool quality_check_success = true;

                    double reflectance_y_mean = reflectance.YMean();
                    if (reflectance_y_mean > ResultData.MAX_BLACK_REFERENCE_REFLECTANCE_LIMIT)
                        quality_check_success = false;


                    black_session_results.BlackResults.Add(new BlackResult()
                    {
                        SerialNumber = black_spectrum.Key,
                        BlackQualityAssuranceCheck = quality_check_success,
                        BlackReferenceCheckResult = check_result
                    });
                }
                this.BlackSessionResults.Add(black_session_results);
            }
        }

        internal PdfTableStringCell[,] GetBlackReferenceEvaluationData(int session_id)
        {
            List<BlackResult> results = this.BlackSessionResults
                                            .First(x => x.SessionNumber == session_id)
                                            .BlackResults;

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

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

                if (item.BlackReferenceCheckResult.Success == true && item.BlackQualityAssuranceCheck)
                {
                    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}",
                                                           item.BlackReferenceCheckResult.IntensityMean.ToString("#0.000"),
                                                           item.BlackReferenceCheckResult.IntensityMeanThreshold.ToString("#0.000"));
                */
                index++;
            }

            return table_data;
        }
    }
}