//
//  OnlineProcessing.cs
//
// QuickStep: Acquire, view and identify spectra 
// Copyright (C) 2010-2017  Thomas Klose & Torsten Schache, 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.Collections.Generic;
using System.IO;
using Gtk;

using Hiperscan.Spectroscopy;
using Hiperscan.FileIO;
using Hiperscan.SGS;
using Hiperscan.Extensions;
using Hiperscan.Unix;
using Hiperscan.GtkExtensions.Widgets;

namespace Hiperscan.Extensions.OnlineProcessing
{
	internal class OnlineProcessing
	{
		private static Dictionary<string,Finder> finders = new Dictionary<string,Finder>();
		public volatile static string ReferencesPath = string.Empty;
		public volatile static bool NoReferencePath = false;
		
		public static void Acquire(Device dev, bool fluid, bool stream, int count, int ix)
		{
			Finder finder = OnlineProcessing.GetFinder(dev);
			finder.ExternalReferenceAveraging = 2000;
			
			string path = GetReferencesPath();

			if (Directory.Exists(path) == false && string.IsNullOrEmpty(path) == false)
				Directory.CreateDirectory(path);

			if (!string.IsNullOrEmpty(path))
			{
				finder.AutoSaveDirectory = path;
				finder.AutoSaveReferences = true;
			}
			else
			{
				finder.AutoSaveReferences = false;
			}

			if (count > 1 && ix == 0)
				finder.ExternalCalibrationFinished += OnlineProcessing.OnExternalCalibrationFinished;

			finder.Acquire(fluid);

			if (count > 1 && ix == 0)
				finder.ExternalCalibrationFinished -= OnlineProcessing.OnExternalCalibrationFinished;

			finder.SaveReferenceSpectrum(finder.CurrentSampleSpectrum, 
			                             fluid ? SpectrumType.FluidSpecimen : SpectrumType.SolidSpecimen,
			                             false, string.Empty);
			Spectrum processed_spectrum = finder.Process(fluid);
			processed_spectrum.IsFromFile = false;
			if (stream)
				processed_spectrum.Id = "5_stream" + dev.Info.SerialNumber;
			Plugin.host.AddToCurrentPlot(processed_spectrum);
		}

		private static void OnExternalCalibrationFinished(bool success)
		{
			if (success)
				Plugin.host.ShowInfoMessage(Plugin.host.MainWindow, Catalog.GetString("Place sample on spectrometer (again)."));
		}
		
		public static void AcquireEmptyDie(Device dev)
		{
			Finder finder = OnlineProcessing.GetFinder(dev);
			
			string path = GetReferencesPath();
			if (!string.IsNullOrEmpty(path))
			{
				finder.AutoSaveDirectory = path;
				finder.AutoSaveReferences = true;
			}
			else
			{
				finder.AutoSaveReferences = false;
			}

			finder.AcquireExternalTransflectanceReference(false);
		}
		
		public static void Reset()
		{
			OnlineProcessing.ReferencesPath = string.Empty;
			OnlineProcessing.NoReferencePath = false;

			foreach (Finder finder in finders.Values)
			{
				finder.ResetReferences();
			}
		}
		
		private static Finder GetFinder(Device dev)
		{
			string serial = dev.Info.SerialNumber;
			
			if (!finders.ContainsKey(serial))
			{
				Finder new_finder = new Finder(dev, ReferenceWheelVersion.Auto, ExternalWhiteReferenceType.Zenith, Plugin.name);
				new_finder.IdleTaskHandler = Plugin.host.ProcessEvents;

				new_finder.WaitForExternalEmptyReference += delegate() 
				{
					FinderReferenceDialog dialog = new FinderReferenceDialog(Plugin.host.MainWindow, FinderReferenceType.ExternalBlack);
					dialog.Run();
				};
				
				new_finder.WaitForExternalWhiteReference += delegate() 
				{
					FinderReferenceDialog dialog = new FinderReferenceDialog(Plugin.host.MainWindow, FinderReferenceType.ExternalWhiteZenith);
					dialog.Run();
				};

				new_finder.UseCorrelationsReferenceChecks = false;
				finders.Add(serial, new_finder);
			}
			
			return finders[serial];
		}
		
		private static string GetReferencesPath()
		{
			if (string.IsNullOrEmpty(OnlineProcessing.ReferencesPath) && !OnlineProcessing.NoReferencePath)
			{
				FileChooserDialog dialog = new FileChooserDialog(Catalog.GetString("Choose raw data 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)
					OnlineProcessing.ReferencesPath = Path.Combine(dialog.Filename, Catalog.GetString("Online Processing Raw Data ").Trim());
				else
					OnlineProcessing.NoReferencePath = true;
				dialog.Destroy();
			}

			return OnlineProcessing.ReferencesPath;
		}
	}
}
