
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.Benchtop.FinderSetup;
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;
            Plugin.InitTestProcess(true, sample_insert_mode);

			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.SetFinderPosition(FinderWheelPosition.Sample, null);

							ushort sav_average = dev.CurrentConfig.Average;
							if (sample_insert_mode)
							{
								if (dev.FinderVersion.SpectrometerType == SpectrometerType.ES20)
                                    dev.CurrentConfig.Average = Settings.Current.AcquisitionAverageEs20SI;
								else
                                    dev.CurrentConfig.Average = Settings.Current.AcquisitionAverageSgsSI;
							}
							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 spectrum: {0}"), ex.Message);
			}

			host.UpdateProperties();
		}

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

			Running = true;
			Plugin.host.MainWindow.Sensitive = false;
            Plugin.InitTestProcess(false, 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.SetFinderPosition(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 spectrum: {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.SetFinderPosition(FinderWheelPosition.Sample, null);

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

						string fname = SpectrumFileNames.GetExternalWhite(white_spectrum);
						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)
							FileIO.CreateDirectory(qs_home);

						string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);

						lock (Handlers.create_directory_mutex)
							FileIO.CreateDirectory(data_dir);

						string white_dir = Path.Combine(data_dir, SpectrumDirNames.EXTERNAL_WHITE);
						Plugin.host.SetCreator(white_spectrum);

						lock (Handlers.create_directory_mutex)
							FileIO.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.SetFinderPosition(FinderWheelPosition.Sample, host.ProcessEvents);

						ushort sav_average = dev.CurrentConfig.Average;
						dev.CurrentConfig.Average = Settings.Current.ExternalReferenceAverage;
						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 = SpectrumFileNames.GetExternalBlack(black_spectrum);
						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)
							FileIO.CreateDirectory(qs_home);

						string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);


						lock (Handlers.create_directory_mutex)
							FileIO.CreateDirectory(data_dir);

						string black_ref_dir = Path.Combine(data_dir, SpectrumDirNames.EXTERNAL_BLACK);
						Plugin.host.SetCreator(black_spectrum);

						lock (Handlers.create_directory_mutex)
							FileIO.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 Blank 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.SetFinderPosition(FinderWheelPosition.Sample, host.ProcessEvents);

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

					string fname = SpectrumFileNames.GetLabsphere(spectrum);
					spectrum.Id = $"1_%%reference%%_{dev.Info.SerialNumber}";
					dev.SetAbsorbance(spectrum);
					dev.SetWavelengthCorrection(spectrum);
					spectrum.Label += " Labsphere";
					spectrum.SpectrumType = SpectrumType.ExternalWhite;

					string qs_home = GetSavePath();
					FileIO.CreateDirectory(qs_home);

					string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);
					FileIO.CreateDirectory(data_dir);

					string labsphere_dir = Path.Combine(data_dir, "Labsphere");
					Plugin.host.SetCreator(spectrum);
					FileIO.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.SetFinderPosition(FinderWheelPosition.Sample, host.ProcessEvents);

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

						string fname = SpectrumFileNames.GetExternalWhiteZenith(extwhite);
						if (sample_insert_mode)
							fname = SpectrumFileNames.GetExternalWhiteZenithInsert(extwhite);

						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 values are less than the TiO2 intensity values. Please repeat external referencing."));
							}
						}

						string qs_home = GetSavePath();

						lock (Handlers.create_directory_mutex)
							FileIO.CreateDirectory(qs_home);

						string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);

						lock (Handlers.create_directory_mutex)
							FileIO.CreateDirectory(data_dir);

						string zenith_dir = Path.Combine(data_dir, SpectrumDirNames.EXTERNAL_WHITE);

						if (sample_insert_mode)
							zenith_dir = Path.Combine(data_dir, SpectrumDirNames.EXTERNAL_WHITE_INSERT);

						Plugin.host.SetCreator(extwhite);

						lock (Handlers.create_directory_mutex)
							FileIO.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 standard: {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.SetFinderPosition(FinderWheelPosition.Sample, host.ProcessEvents);

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


					string fname = SpectrumFileNames.GetExternalTransflectance(spectrum);
					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();
					FileIO.CreateDirectory(qs_home);

					string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);
					FileIO.CreateDirectory(data_dir);

					string white_dir = Path.Combine(data_dir, SpectrumDirNames.EXTERNAL_TRANSFLECTANCE);
					Plugin.host.SetCreator(spectrum);
					FileIO.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)
		{
            SampleIdWindow.SerialNumber = String.Empty;
			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.InternalCalibrationAverage;
			dev.WriteConfig();

			// dark intensity
			dev.SetFinderPosition(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.SetFinderPosition(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.SetFinderPosition(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((byte)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();
			FileIO.CreateDirectory(qs_home);

			string data_dir = Path.Combine(qs_home, SpectrumDirNames.REFERENCING);
			FileIO.CreateDirectory(data_dir);

			string di_dir = Path.Combine(data_dir, SpectrumDirNames.INTERNAL_DARK);
			Plugin.host.SetCreator(di_spectrum);
			FileIO.CreateDirectory(di_dir);
			di_spectrum.SpectrumType = SpectrumType.InternalDark;

            CSV.Write(di_spectrum, Path.Combine(di_dir, SpectrumFileNames.GetInternalDark(di_spectrum)));

			string iw_dir = Path.Combine(data_dir, SpectrumDirNames.INTERNAL_WHITE);
			Plugin.host.SetCreator(iw_spectrum);
			FileIO.CreateDirectory(iw_dir);
			iw_spectrum.SpectrumType = SpectrumType.InternalWhite;

            CSV.Write(iw_spectrum, Path.Combine(iw_dir, SpectrumFileNames.GetInternalWhite(iw_spectrum)));

			string rf_dir = Path.Combine(data_dir, SpectrumDirNames.INTERNAL_OXIDE);
			Plugin.host.SetCreator(rf_spectrum);
			FileIO.CreateDirectory(rf_dir);
			rf_spectrum.SpectrumType = SpectrumType.InternalOxid;

            CSV.Write(rf_spectrum, Path.Combine(rf_dir, SpectrumFileNames.GetInternalOxide(rf_spectrum)));

			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("One or several instruments exceed the defined temperature limit of {0}°C."),
						       DEVICE_TEMPERATURE_UPPER_LIMIT);

			CheckButton cb = new CheckButton(Catalog.GetString("Do not show this dialogue 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;
		}
    }
}
