
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;

using Gtk;

using Hiperscan.Common;
using Hiperscan.SGS;
using Hiperscan.SGS.Benchtop;
using Hiperscan.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Unix;


namespace Hiperscan.Extensions.Acquisition
{

    public static class Handlers
    {
        private const double DEVICE_TEMPERATURE_UPPER_LIMIT = 45.0;

        public static string AutoSaveFirstFilename = string.Empty;
        public volatile static bool Running = false;
        public volatile static string SavePath = string.Empty;
        public volatile static bool NeedClearPlot = false;

        private static ConcurrentDictionary<string,Spectrum> _current_tio2_spectra = new ConcurrentDictionary<string,Spectrum>();
        private static ConcurrentDictionary<string,Finder> _finders = new ConcurrentDictionary<string,Finder>();

        private static readonly bool no_wavelength_correction = Environment.GetEnvironmentVariable(Env.Plugin.ACQUISITION_NO_WLC) == "1";
        private static readonly bool no_plausibility_checks   = Environment.GetEnvironmentVariable(Env.Plugin.ACQUISITION_NO_PLAUSIBILITY_CHECKS) == "1";

        private static object create_directory_mutex = new object();

        public static bool IgnoreDeviceTemperatures { get; private set; }


        public static void OnAutoSolidClicked(IHost host, bool sample_insert_mode)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            Running = true;
            Plugin.host.MainWindow.Sensitive = false;

            try
            {
                Plugin.acquisition_count_spin.Update();

                if (Handlers.NeedClearPlot)
                {
                    Plugin.host.ClearPlot();
                    Handlers.NeedClearPlot = false;
                }

                for (int ix = 0; ix < Plugin.acquisition_count_spin.Value; ++ix)
                {
                    ConcurrentBag<Spectrum> current_spectra = new ConcurrentBag<Spectrum>();
                    ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception>();
                    
                    AForge.Parallel.ThreadsCount = host.ActiveDevices.Connected.Count;
                    AForge.Parallel.For(0, host.ActiveDevices.Connected.Count, jx =>
                    {

                        try
                        {
                            IDevice dev = host.ActiveDevices.Connected[jx];

                            if (dev.IsFinder == false)
                                return;

                            dev.WaitForIdle(5000);

                            dev.SetFinderWheel(FinderWheelPosition.Sample, null);

                            ushort sav_average = dev.CurrentConfig.Average;
                            if (sample_insert_mode)
                                dev.CurrentConfig.Average = 2000;
                            else
                                dev.CurrentConfig.Average = Settings.Current.AcquisitionAverage;
                            dev.WriteConfig();

                            Spectrum current_spectrum = dev.Single(true, null);
                            SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                            current_spectrum.SpectrumType = SpectrumType.SolidSpecimen;

                            if (sample_insert_mode)
                            {
                                if (current_spectrum.ProbeType == ProbeType.FinderSDStandard)
                                    current_spectrum.ProbeType = ProbeType.FinderSDInsert;
                                else
                                    current_spectrum.ProbeType = ProbeType.FinderInsert;
                            }

                            dev.CurrentConfig.Average = sav_average;
                            dev.WriteConfig();

                            if (dev.AutoRecalibrationIsPending)
                                Handlers.Recalibrate(dev, null);

                            dev.SetAbsorbance(current_spectrum);
                            dev.SetWavelengthCorrection(current_spectrum);

                            current_spectra.Add(current_spectrum);
                        }
                        catch (Exception ex)
                        {
                            exceptions.Add(ex);
                        }
                    });

                    if (exceptions.Count > 0)
                        throw exceptions.ToArray()[0];

                    foreach (Spectrum spectrum in current_spectra)
                    {
                        host.AddToCurrentPlot(spectrum);
                    }
                    host.FitPlot();
                    host.ProcessEvents();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition with auto-recalibration: {0}"),
                                     ex.ToString());
            }
            finally
            {
                Running = false;
                Plugin.host.MainWindow.Sensitive = true;
            }

            try
            {
                if (string.IsNullOrEmpty(Handlers.AutoSaveFirstFilename) == false)
                    host.SaveAll(host.CurrentSpectra, Handlers.AutoSaveFirstFilename, true);

                Handlers.AutoSaveFirstFilename = string.Empty;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                Plugin.host.ShowInfoMessage(Plugin.host.MainWindow,
                                            Catalog.GetString("Cannot save spectra: {0}"), ex.Message);
            }

            host.UpdateProperties();
        }

        public static void OnAutoFluidClicked(IHost host)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            Running = true;

            Plugin.host.MainWindow.Sensitive = false;

            try
            {
                if (Plugin.SampleInsertMode)
                    throw new Exception(Catalog.GetString("Sample Insert mode is not supported for transflectance measurements."));

                Plugin.acquisition_count_spin.Update();

                for (int ix = 0; ix < Plugin.acquisition_count_spin.Value; ++ix)
                {
                    foreach (IDevice dev in host.ActiveDevices.Connected)
                    {
                        if (dev.IsFinder == false)
                            continue;

                        if (Handlers.NeedClearPlot)
                        {
                            Plugin.host.ClearPlot();
                            Handlers.NeedClearPlot = false;
                        }

                        dev.WaitForIdle(5000);

                        dev.SetFinderWheel(FinderWheelPosition.Sample, host.ProcessEvents);

                        ushort sav_average = dev.CurrentConfig.Average;
                        dev.CurrentConfig.Average = Settings.Current.AcquisitionAverage;
                        dev.WriteConfig();
                        Spectrum current_spectrum = dev.Single(true, Plugin.host.ProcessEvents);
                        //Handlers.GetFinder(dev).ResetRecalibrationTimestamp();
                        SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                        current_spectrum.SpectrumType = SpectrumType.FluidSpecimen;
                        dev.CurrentConfig.Average = sav_average;
                        dev.WriteConfig();

                        dev.SetAbsorbance(current_spectrum);
                        dev.SetWavelengthCorrection(current_spectrum);

                        host.AddToCurrentPlot(current_spectrum);
                        host.FitPlot();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition with auto-recalibration: {0}"),
                                     ex.Message);
            }
            finally
            {
                
                Running = false;
                Plugin.host.MainWindow.Sensitive = true;

            }

            try
            {
                if (string.IsNullOrEmpty(Handlers.AutoSaveFirstFilename) == false)
                    host.SaveAll(host.CurrentSpectra, Handlers.AutoSaveFirstFilename, true);

                Handlers.AutoSaveFirstFilename = string.Empty;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                Plugin.host.ShowInfoMessage(Plugin.host.MainWindow, Catalog.GetString("Cannot save spectra: {0}"), ex.Message);
            }

            host.UpdateProperties();
        }

        public static void OnTitanClicked(IHost host)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            try
            {
                Plugin.host.MainWindow.Sensitive = false;

                Handlers.GetSavePath();
                host.ProcessEvents();

                ConcurrentBag<Spectrum> current_spectra = new ConcurrentBag<Spectrum>();
                ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception>();

                AForge.Parallel.ThreadsCount = host.ActiveDevices.Connected.Count;
                AForge.Parallel.For(0, host.ActiveDevices.Connected.Count, jx =>
                {

                    try
                    {
                        IDevice dev = host.ActiveDevices.Connected[jx];

                        if (dev.IsFinder == false)
                            return;

                        dev.WaitForIdle(5000);

                        if (dev.AutoRecalibrationIsPending)
                            Handlers.Recalibrate(dev, host.ProcessEvents);

                        dev.SetFinderWheel(FinderWheelPosition.Sample, null);

                        ushort sav_average = dev.CurrentConfig.Average;
                        dev.CurrentConfig.Average = Settings.Current.ReferenceAverage;
                        dev.WriteConfig();
                        Spectrum white_spectrum = dev.Single(true, null);
                        SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                        dev.CurrentConfig.Average = sav_average;
                        dev.WriteConfig();

                        string fname = white_spectrum.Id.Remove(0, 2) + "_extwhite";
                        white_spectrum.Id = $"1_%%reference%%_{dev.Info.SerialNumber}";
                        dev.SetAbsorbance(white_spectrum);
                        dev.SetWavelengthCorrection(white_spectrum);
                        white_spectrum.Label += " " + Catalog.GetString("White Reference");
                        white_spectrum.SpectrumType = SpectrumType.ExternalWhite;

                        if (Handlers.no_plausibility_checks == false)
                            Handlers.GetFinder(dev).CheckWhiteReference(white_spectrum);

                        string qs_home = GetSavePath();
                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(qs_home) == false)
                                Directory.CreateDirectory(qs_home);
                        }

                        string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(data_dir) == false)
                                Directory.CreateDirectory(data_dir);
                        }

                        string white_dir = Path.Combine(data_dir, Catalog.GetString("White Reference"));
                        Plugin.host.SetCreator(white_spectrum);

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(white_dir) == false)
                                Directory.CreateDirectory(white_dir);
                        }

                        CSV.Write(white_spectrum, Path.Combine(white_dir, fname));

                        Handlers.SetCurrentTiO2Spectrum(dev, white_spectrum);

                        current_spectra.Add(white_spectrum);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                });

                if (exceptions.Count > 0)
                {
                    Console.WriteLine(exceptions.ToArray()[0]);
                    throw exceptions.ToArray()[0];
                }

                foreach (Spectrum spectrum in current_spectra)
                {
                    host.AddToCurrentPlot(spectrum);
                }
                host.FitPlot();
                host.ProcessEvents();

                Handlers.NeedClearPlot = true;

                //                    Plugin.toolbar_info1.IsSensitive = true;
                Plugin.LastExtwhiteTime = DateTime.Now;
                Plugin.LastTransflectanceInsertReferenceTime = DateTime.MinValue;
                Plugin.ResetExternalReferences(new TimeSpan(0, 10, 0));
                Plugin.UpdateControls();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition of White Standard spectrum: {0}"),
                                     ex.Message);
            }
            finally
            {
                Plugin.host.MainWindow.Sensitive = true;
            }

            host.UpdateProperties();
        }

        public static void OnEmptyClicked(IHost host)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            try
            {
                Plugin.host.MainWindow.Sensitive = false;

                Handlers.GetSavePath();
                host.ProcessEvents();

                ConcurrentBag<Spectrum> current_spectra = new ConcurrentBag<Spectrum>();
                ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception>();

                AForge.Parallel.ThreadsCount = host.ActiveDevices.Connected.Count;
                AForge.Parallel.For(0, host.ActiveDevices.Connected.Count, jx =>
                {

                    try
                    {
                        IDevice dev = host.ActiveDevices.Connected[jx];

                        if (dev.IsFinder == false)
                            return;

                        dev.WaitForIdle(5000);

                        if (dev.AutoRecalibrationIsPending)
                            Handlers.Recalibrate(dev, host.ProcessEvents);

                        dev.SetFinderWheel(FinderWheelPosition.Sample, host.ProcessEvents);

                        ushort sav_average = dev.CurrentConfig.Average;
                        dev.CurrentConfig.Average = Settings.Current.ReferenceAverage;
                        dev.WriteConfig();
                        Spectrum black_spectrum = dev.Single(true, Plugin.host.ProcessEvents);
                        SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                        dev.CurrentConfig.Average = sav_average;
                        dev.WriteConfig();

                        string fname = black_spectrum.Id.Remove(0, 2) + "_extblack";
                        black_spectrum.Id = $"1_%%reference%%_{dev.Info.SerialNumber}";
                        dev.SetAbsorbance(black_spectrum);
                        dev.SetWavelengthCorrection(black_spectrum);
                        black_spectrum.Label += " " + Catalog.GetString("Black Reference");
                        black_spectrum.SpectrumType = SpectrumType.ExternalEmpty;

                        if (Handlers.no_plausibility_checks == false)
                            Handlers.GetFinder(dev).CheckBlackReference(black_spectrum);

                        string qs_home = GetSavePath();

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(qs_home) == false)
                                Directory.CreateDirectory(qs_home);
                        }

                        string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));


                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(data_dir) == false)
                                Directory.CreateDirectory(data_dir);
                        }

                        string black_ref_dir = Path.Combine(data_dir, Catalog.GetString("Black Reference"));
                        Plugin.host.SetCreator(black_spectrum);

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(black_ref_dir) == false)
                                Directory.CreateDirectory(black_ref_dir);
                        }
                        CSV.Write(black_spectrum, Path.Combine(black_ref_dir, fname));

                        current_spectra.Add(black_spectrum);

                        Handlers.GetFinder(dev).__SetSpectra(null, null, null, null, null, null, black_spectrum, null, null, null);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                });

                if (exceptions.Count > 0)
                    throw exceptions.ToArray()[0];

                foreach (Spectrum spectrum in current_spectra)
                {
                    host.AddToCurrentPlot(spectrum);
                }

                host.FitPlot();
                host.ProcessEvents();

                Handlers.NeedClearPlot = true;

                Plugin.LastExtemptyTime = DateTime.Now;
                Plugin.ResetExternalReferences(new TimeSpan(0, 10, 0));

                Plugin.UpdateControls();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition of Empty Standard spectrum: {0}"),
                                     ex.Message);
            }
            finally
            {
                Plugin.host.MainWindow.Sensitive = true;
            }

            host.UpdateProperties();
        }

        public static void OnLabsphereClicked(IHost host)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            try
            {
                Plugin.host.MainWindow.Sensitive = false;

                if (Plugin.SampleInsertMode)
                    throw new Exception(Catalog.GetString("Sample Insert mode is not supported for Labsphere measurements."));

                foreach (IDevice dev in host.ActiveDevices.Connected)
                {
                    if (dev.IsFinder == false)
                        continue;

                    dev.WaitForIdle(5000);

                    dev.SetFinderWheel(FinderWheelPosition.Sample, host.ProcessEvents);

                    ushort sav_average = dev.CurrentConfig.Average;
                    dev.CurrentConfig.Average = Settings.Current.ReferenceAverage;
                    dev.WriteConfig();
                    Spectrum spectrum = dev.Single(true, Plugin.host.ProcessEvents);
                    SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                    dev.CurrentConfig.Average = sav_average;
                    dev.WriteConfig();

                    string fname = spectrum.Id.Remove(0, 2) + "_labsphere";
                    spectrum.Id = $"1_%%reference%%_{dev.Info.SerialNumber}";
                    dev.SetAbsorbance(spectrum);
                    dev.SetWavelengthCorrection(spectrum);
                    spectrum.Label += " Labsphere";
                    spectrum.SpectrumType = SpectrumType.ExternalWhite;

                    string qs_home = GetSavePath();
                    if (Directory.Exists(qs_home) == false)
                        Directory.CreateDirectory(qs_home);

                    string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));
                    if (Directory.Exists(data_dir) == false)
                        Directory.CreateDirectory(data_dir);

                    string labsphere_dir = Path.Combine(data_dir, "Labsphere");
                    Plugin.host.SetCreator(spectrum);
                    if (Directory.Exists(labsphere_dir) == false)
                        Directory.CreateDirectory(labsphere_dir);
                    CSV.Write(spectrum, Path.Combine(labsphere_dir, fname));

                    host.AddToCurrentPlot(spectrum);
                    host.FitPlot();

                    Handlers.NeedClearPlot = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition of Labsphere spectrum: {0}"),
                                     ex.Message);
            }
            finally
            {
                Plugin.host.MainWindow.Sensitive = true;
            }

            host.UpdateProperties();
        }

        public static void OnZenithClicked(IHost host, bool sample_insert_mode)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            try
            {
                Plugin.host.MainWindow.Sensitive = false;

                Handlers.GetSavePath();
                host.ProcessEvents();

                ConcurrentBag<Spectrum> current_spectra = new ConcurrentBag<Spectrum>();
                ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception>();

                AForge.Parallel.ThreadsCount = host.ActiveDevices.Connected.Count;
                AForge.Parallel.For(0, host.ActiveDevices.Connected.Count, jx =>
                {

                    try
                    {
                        IDevice dev = host.ActiveDevices.Connected[jx];

                        if (dev.IsFinder == false)
                            return;

                        dev.WaitForIdle(5000);

                        if (dev.AutoRecalibrationIsPending)
                            Handlers.Recalibrate(dev, host.ProcessEvents);

                        dev.SetFinderWheel(FinderWheelPosition.Sample, host.ProcessEvents);

                        ushort sav_average = dev.CurrentConfig.Average;
                        dev.CurrentConfig.Average = Settings.Current.ReferenceAverage;
                        dev.WriteConfig();
                        Spectrum extwhite = dev.Single(true, Plugin.host.ProcessEvents);
                        SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                        dev.CurrentConfig.Average = sav_average;
                        dev.WriteConfig();

                        string fname = extwhite.Id.Remove(0, 2) + "_extzenith";
                        if (sample_insert_mode)
                            fname = extwhite.Id.Remove(0, 2) + "_zenith_insert";

                        extwhite.Id = $"1_%%reference%%_{dev.Info.SerialNumber}";
                        dev.SetAbsorbance(extwhite);
                        dev.SetWavelengthCorrection(extwhite);

                        extwhite.Label += " Zenith";
                        if (sample_insert_mode)
                            extwhite.Label += " Insert";

                        extwhite.SpectrumType = SpectrumType.ExternalWhite;

                        if (sample_insert_mode)
                        {
                            if (extwhite.ProbeType == ProbeType.FinderSDStandard)
                                extwhite.ProbeType = ProbeType.FinderSDInsert;
                            else
                                extwhite.ProbeType = ProbeType.FinderInsert;

                            if (Handlers.no_plausibility_checks == false)
                                Handlers.GetFinder(dev).CheckSampleInsertWhiteReference(extwhite);
                        }
                        else
                        {
                            if (Handlers.no_plausibility_checks == false)
                                Handlers.GetFinder(dev).CheckWhiteReference(extwhite);

                            if (Environment.GetEnvironmentVariable(Env.Plugin.ACQUISITION_NO_PLAUSIBILITY_CHECKS) != "1" &&
                                Handlers.GetCurrentTiO2Spectrum(dev) != null &&
                                Handlers.GetCurrentTiO2Spectrum(dev).Intensity.YMax() > extwhite.Intensity.YMax())
                            {
                                throw new Exception(Catalog.GetString("Zenith intensity is less than TiO2 intensity. " +
                                                                      "Please repeat external referencing."));
                            }
                        }

                        string qs_home = GetSavePath();

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(qs_home) == false)
                                Directory.CreateDirectory(qs_home);
                        }

                        string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(data_dir) == false)
                                Directory.CreateDirectory(data_dir);
                        }

                        string zenith_dir = Path.Combine(data_dir, "Zenith");

                        if (sample_insert_mode)
                            zenith_dir = Path.Combine(data_dir, "Zenith Insert");

                        Plugin.host.SetCreator(extwhite);

                        lock (Handlers.create_directory_mutex)
                        {
                            if (Directory.Exists(zenith_dir) == false)
                                Directory.CreateDirectory(zenith_dir);
                        }

                        CSV.Write(extwhite, Path.Combine(zenith_dir, fname));
                        current_spectra.Add(extwhite);

                        Handlers.GetFinder(dev).__SetSpectra(null, null, null, null, extwhite, null, null,
                                                             Handlers.GetFinder(dev).CurrentInternalOxidSpectrum,
                                                             Handlers.GetFinder(dev).CurrentInternalWhiteSpectrum,
                                                             Handlers.GetFinder(dev).CurrentInternalDarkSpectrum);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                });

                if (exceptions.Count > 0)
                    throw exceptions.First();

                foreach (Spectrum spectrum in current_spectra)
                {
                    host.AddToCurrentPlot(spectrum);
                }

                host.FitPlot();
                host.ProcessEvents();

                Handlers.NeedClearPlot = true;

                if (sample_insert_mode)
                    Plugin.LastSampleInsertZenithTime = DateTime.Now;
                else
                    Plugin.LastZenithTime = DateTime.Now;
                Plugin.ResetExternalReferences(new TimeSpan(0, 10, 0));

                Plugin.UpdateControls();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition of white reference spectrum: {0}"),
                                     ex.Message);
            }
            finally
            {
                Plugin.host.MainWindow.Sensitive = true;
            }

            host.UpdateProperties();
        }

        public static void OnTransflectanceInsertClicked(IHost host)
        {
            if (Handlers.CheckDeviceTemperatures(host) == false)
                return;

            try
            {
                Plugin.host.MainWindow.Sensitive = false;

                if (Plugin.SampleInsertMode)
                    throw new Exception(Catalog.GetString("Sample Insert mode is not supported for transflectance measurements."));

                foreach (IDevice dev in host.ActiveDevices.Connected)
                {
                    if (dev.IsFinder == false)
                        continue;

                    dev.WaitForIdle(5000);

                    if (dev.AutoRecalibrationIsPending)
                        Handlers.Recalibrate(dev, host.ProcessEvents);

                    dev.SetFinderWheel(FinderWheelPosition.Sample, host.ProcessEvents);

                    ushort sav_average = dev.CurrentConfig.Average;
                    dev.CurrentConfig.Average = Settings.Current.ReferenceAverage;
                    dev.WriteConfig();
                    Spectrum spectrum = dev.Single(true, Plugin.host.ProcessEvents);
                    SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
                    dev.CurrentConfig.Average = sav_average;
                    dev.WriteConfig();


                    string fname = spectrum.Id.Remove(0, 2) + "_transflectref";
                    spectrum.Id = $"1_%%transflectref%%_{dev.Info.SerialNumber}";
                    spectrum.Label += " " + Catalog.GetString("Transflectance Insert");
                    spectrum.SpectrumType = SpectrumType.ExternalFluidWhite;

                    dev.SetWavelengthCorrection(spectrum);
                    dev.CurrentConfig.ReferenceSpectrum = spectrum.Clone();

                    if (Handlers.no_plausibility_checks == false)
                    {
                        Finder finder = Handlers.GetFinder(dev);

                        if (finder.CurrentExternalWhiteSpectrum != null)
                            finder.CheckTransflectanceInsert(spectrum,
                                 finder.CurrentExternalWhiteSpectrum,
                                 finder.Device.CurrentConfig.DarkIntensity);
                    }

                    string qs_home = GetSavePath();
                    if (Directory.Exists(qs_home) == false)
                        Directory.CreateDirectory(qs_home);

                    string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));
                    if (Directory.Exists(data_dir) == false)
                        Directory.CreateDirectory(data_dir);

                    string white_dir = Path.Combine(data_dir, Catalog.GetString("Transflectance Insert"));
                    Plugin.host.SetCreator(spectrum);
                    if (Directory.Exists(white_dir) == false)
                        Directory.CreateDirectory(white_dir);
                    CSV.Write(spectrum, Path.Combine(white_dir, fname));

                    host.AddToCurrentPlot(spectrum);
                    host.FitPlot();

                    Handlers.NeedClearPlot = true;

                    Plugin.LastTransflectanceInsertReferenceTime = DateTime.Now;
                    Plugin.UpdateControls();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                host.ShowInfoMessage(Plugin.host.MainWindow,
                                     Catalog.GetString("Error while acquisition of Transflectance Insert spectrum: {0}"),
                                     ex.Message);
            }
            finally
            {
                Plugin.host.MainWindow.Sensitive = true;
            }

            host.UpdateProperties();
        }

        public static void OnSaveAllClicked(IHost host)
        {
            var w = new SampleIdWindow();
        }

        public static void OnSaveAfterAcquisitionClicked(IHost host)
        {
            var c = new LocationChooser();
        }

        public static void OnResetReferencePathClicked(IHost host)
        {
            Handlers.SavePath = string.Empty;
        }

        private static void Recalibrate(IDevice dev, IdleTaskHandler idle_handler)
        {
            dev.CurrentConfig.WavelengthCorrection = null;

            ushort sav_average = dev.CurrentConfig.Average;
            dev.CurrentConfig.Average = Settings.Current.AcquisitionAverage;
            dev.WriteConfig();

            // dark intensity
            dev.SetFinderWheel(FinderWheelPosition.White, idle_handler);
            Spectrum di_spectrum = dev.Single(false);
            SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
            dev.CurrentConfig.DarkIntensity = new DarkIntensity(di_spectrum.RawIntensity.YMean(),
                                                                di_spectrum.RawIntensity.YSigma());
            dev.CurrentConfig.DarkIntensityType = Spectrometer.DarkIntensityType.Record;

            // reference
            dev.SetFinderWheel(FinderWheelPosition.White, idle_handler);
            Spectrum iw_spectrum = dev.Single(true, idle_handler);
            SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
            dev.CurrentConfig.ReferenceSpectrum = new Spectrum(iw_spectrum);
            dev.CurrentConfig.ReferenceSpectrumType = Spectrometer.ReferenceSpectrumType.Record;

            // calibration
            dev.SetFinderWheel(FinderWheelPosition.Reference, idle_handler);
            Spectrum rf_spectrum = dev.Single(true, idle_handler);
            SampleIdWindow.SerialNumber = dev.Info.SerialNumber;
            dev.CurrentConfig.Average = sav_average;
            dev.WriteConfig();
            dev.SetAbsorbance(rf_spectrum);
            rf_spectrum.LimitBandwidth = true;

            if (Handlers.no_wavelength_correction == false)
            {
                if ((int)dev.FinderVersion.ReferenceWheel < 2)
                {
                    DataSet references = WavelengthCorrection.GetWavelengthReferences(WavelengthCorrection.ReferenceType.NIST15nm);
                    dev.CurrentConfig.WavelengthCorrection = WavelengthCorrection.Calculate(references, rf_spectrum.Absorbance.SNV());
                }
                else
                {
                    Spectrum ref_spectrum = Finder.GetWavelengthReference(dev.FinderVersion.ReferenceWheel);
                    if (Finder.HasZenithRecalibrationReference(dev))
                    {
                        dev.CurrentConfig.WavelengthCorrection = new WavelengthCorrection(ref_spectrum,
                                                                                          rf_spectrum,
                                                                                          Finder.ZenithRecalibrationWavelengths,
                                                                                          false);
                    }
                    else
                    {
                        dev.CurrentConfig.WavelengthCorrection = new WavelengthCorrection(ref_spectrum, rf_spectrum, null, true);
                    }
                }
            }

            dev.SetWavelengthCorrection(rf_spectrum);

            dev.CalibrationInfo = new CalibrationInfo(DateTime.Now,
                                                      dev.Frequency.Y[dev.Frequency.Count - 1],
                                                      2.0, 0.0005);

            string qs_home = GetSavePath();
            if (Directory.Exists(qs_home) == false)
                Directory.CreateDirectory(qs_home);

            string data_dir = Path.Combine(qs_home, Catalog.GetString("Referencing"));
            if (Directory.Exists(data_dir) == false)
                Directory.CreateDirectory(data_dir);

            string di_dir = Path.Combine(data_dir, Catalog.GetString("Dark"));
            Plugin.host.SetCreator(di_spectrum);
            if (Directory.Exists(di_dir) == false)
                Directory.CreateDirectory(di_dir);
            CSV.Write(di_spectrum, Path.Combine(di_dir, di_spectrum.Id.Remove(0, 2) + "_intdark"));

            string iw_dir = Path.Combine(data_dir, Catalog.GetString("White"));
            Plugin.host.SetCreator(iw_spectrum);
            if (Directory.Exists(iw_dir) == false)
                Directory.CreateDirectory(iw_dir);
            CSV.Write(iw_spectrum, Path.Combine(iw_dir, iw_spectrum.Id.Remove(0, 2) + "_intwhite"));

            string rf_dir = Path.Combine(data_dir, Catalog.GetString("Oxide"));
            Plugin.host.SetCreator(rf_spectrum);
            if (Directory.Exists(rf_dir) == false)
                Directory.CreateDirectory(rf_dir);
            CSV.Write(rf_spectrum, Path.Combine(rf_dir, rf_spectrum.Id.Remove(0, 2) + "_intoxid"));

            Handlers.GetFinder(dev).__SetSpectra(null, iw_spectrum, di_spectrum, rf_spectrum, null, null, null, null, null, null);
        }

        internal static string GetSavePath()
        {
            if (string.IsNullOrEmpty(Handlers.SavePath))
            {
                var dialog = new FileChooserDialog(Catalog.GetString("Choose output directory"),
                                                   Plugin.host.MainWindow,
                                                   FileChooserAction.SelectFolder,
                                                   Stock.Open,
                                                   ResponseType.Ok,
                                                   Stock.Cancel,
                                                   ResponseType.Cancel);

                dialog.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
                int choice = dialog.Run();

                if (choice == (int)ResponseType.Ok)
                    Handlers.SavePath = dialog.Filename;

                dialog.Destroy();
            }

            if (string.IsNullOrEmpty(Handlers.SavePath))
            {
                string home = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                string qs_home = Path.Combine(home, ".QuickStep");
                Handlers.SavePath = qs_home;
            }

            if (Handlers.SavePath.EndsWith("_SI", StringComparison.InvariantCulture))
                return Handlers.SavePath.Substring(0, Handlers.SavePath.Length - 3);

            return Handlers.SavePath;
        }

        private static Finder GetFinder(IDevice dev)
        {
            string serial = dev.Info.SerialNumber;

            if (Handlers._finders.ContainsKey(serial) == false)
            {
                foreach (IDevice device in Plugin.host.ActiveDevices.Idle)
                {
                    if (device.IsFinder == false)
                        continue;

                    if (Handlers._finders.ContainsKey(device.Info.SerialNumber))
                        continue;

                    Handlers._finders.TryAdd(device.Info.SerialNumber,
                                             new Finder(dev,
                                                        (ReferenceWheelVersion)dev.FinderVersion.ReferenceWheel,
                                                        ExternalWhiteReferenceType.Zenith, "finder_dummy"));
                }
            }

            return Handlers._finders[serial];
        }

        private static Spectrum GetCurrentTiO2Spectrum(IDevice dev)
        {
            string serial = dev.Info.SerialNumber;

            if (Handlers._current_tio2_spectra.ContainsKey(serial) == false)
                return null;

            return Handlers._current_tio2_spectra[serial];
        }

        private static void SetCurrentTiO2Spectrum(IDevice dev, Spectrum spectrum)
        {
            string serial = dev.Info.SerialNumber;

            if (Handlers._current_tio2_spectra.ContainsKey(serial))
            {
                Handlers._current_tio2_spectra[serial] = spectrum;
            }
            else
            {
                Handlers._current_tio2_spectra.TryAdd(serial, spectrum);
            }
        }

        private static bool CheckDeviceTemperatures(IHost host)
        {
            if (Handlers.IgnoreDeviceTemperatures)
                return true;

            if (host.ActiveDevices.Connected.Any(dev => dev.LastTemperature > DEVICE_TEMPERATURE_UPPER_LIMIT) == false)
                return true;

            var dialog = new MessageDialog(host.MainWindow,
                                           DialogFlags.Modal,
                                           MessageType.Warning,
                                           ButtonsType.OkCancel,
                                           Catalog.GetString("On or several instruments exceed the defined temperature limit of {0}°C."),
                                           DEVICE_TEMPERATURE_UPPER_LIMIT);

            CheckButton cb = new CheckButton(Catalog.GetString("Don't show this dialog again"))
            {
                CanFocus = false
            };
            dialog.VBox.PackStart(cb);
            dialog.ShowAll();
            ResponseType response = (ResponseType)dialog.Run();
            Handlers.IgnoreDeviceTemperatures = cb.Active;

            dialog.Destroy();
            host.ProcessEvents();

            return response == ResponseType.Ok;
        }
    }
}