// Created with MonoDevelop
//
//    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.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using MathNet.Numerics.LinearAlgebra.Double;

using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Spectroscopy.Math;
using Hiperscan.Unix;

namespace Hiperscan.Spectroscopy.Processing.Transformations
{
    public static class FinderXFinderSDTransformer
    {
        private static LinearTransformation linear_transformation_function = null;
        private static volatile bool loaded = false;
        private static object _lock = new object();

        private static void LoadLinearTransformation()
        {
            lock (FinderXFinderSDTransformer._lock)
            {
                if (FinderXFinderSDTransformer.loaded)
                    return;

                if (FinderXFinderSDTransformer.linear_transformation_function != null)
                    return;

                Hiperscan.Spectroscopy.IO.PlainCSV.Separator = ',';
                Dictionary<int, List<string>> matrix_csv = null;
                Dictionary<int, List<string>> vector_csv = null;

                using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Spectroscopy.Processing.Transformations.FinderX.transform_finder_x_finder_sd_matrix.csv"))
                    matrix_csv = PlainCSV.Read(stream);
                    
                using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Spectroscopy.Processing.Transformations.FinderX.transform_finder_x_finder_sd_vector.csv"))
                    vector_csv = PlainCSV.Read(stream);

                //TODO #37345 Change if Quadratic (901x901)
                var matrix = LinearTransformation.ReadDiagonalArrayFromCsv(matrix_csv);
                //var matrix = LinearTransformation.ReadQuadraticArrayFromCsv(matrix_csv);
                var vector = LinearTransformation.ReadArrayFromCsv(vector_csv);

                FinderXFinderSDTransformer.linear_transformation_function = new LinearTransformation(vector, matrix);
                FinderXFinderSDTransformer.loaded = true;
            }
        }

        public static void ApplyTransformation(Spectrum spectrum)
        {
            if (spectrum.SpectrumType != SpectrumType.ProcessedFluidSpecimen && spectrum.SpectrumType != SpectrumType.ProcessedSolidSpecimen)
                throw new ArgumentException(Catalog.GetString("Spectrum must be a processed spectrum"));

            if (spectrum.ProbeType != ProbeType.FinderXInsert && spectrum.ProbeType != ProbeType.FinderXInsert && spectrum.ProbeType != ProbeType.FinderXLineScan)
                throw new ArgumentException(Catalog.GetString("Spectrum must be a Finder SD spectrum"));

            if (spectrum.ProbeType == ProbeType.FinderXInsert)
                return;

            if (spectrum.SpectrumType == SpectrumType.ProcessedFluidSpecimen)
                return;

            if (FinderXFinderSDTransformer.loaded == false)
                FinderXFinderSDTransformer.LoadLinearTransformation();

            FinderXFinderSDTransformer.linear_transformation_function.Transform(spectrum, true, false);
        }
    }
}
