//
//  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.GtkExtensions.Widgets;
using Hiperscan.SGS;
using Hiperscan.SGS.Benchtop;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.Method;
using Hiperscan.Unix;


namespace Hiperscan.Extensions.OnlineProcessing
{

    internal static 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(IDevice dev, SubstanceType substance_type, bool stream, int count, int ix)
        {
            Finder finder = OnlineProcessing.GetFinder(dev, substance_type == SubstanceType.SampleInsertOnly);
            if ((count == 1) || (count > 1 && ix == 0))
                finder.ExternalReferenceAveraging = 2000;
            
            string path = OnlineProcessing.GetReferencesPath();

            if (false == string.IsNullOrEmpty(path))
                FileIO.CreateDirectory(path);

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

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

            bool is_fluid = substance_type == SubstanceType.Fluid;

            finder.Acquire(is_fluid);
            /*
            if (is_fluid)
            {
                finder.AcquireExternalTransflectanceReference();
                finder.Acquire(is_fluid);

            }
            else
            {
                if (count == 1) { 
                    finder.AcquireExternalReflectanceReference(false);
                    Plugin.host.ShowInfoMessage(Plugin.host.MainWindow, Catalog.GetString("Place sample on spectrometer (again)."));
                }
                finder.Acquire(is_fluid);
            }
            */



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

            finder.SaveReferenceSpectrum(finder.CurrentSampleSpectrum,
                                         is_fluid ? SpectrumType.FluidSpecimen : SpectrumType.SolidSpecimen,
                                         false, string.Empty);
            Spectrum processed_spectrum = finder.Process(is_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 the sample on spectrometer (again)."));
        }
        
        public static void AcquireTransflectanceReference(IDevice dev)
        {
            Finder finder = OnlineProcessing.GetFinder(dev, false);
            
            string path = GetReferencesPath();
            if (string.IsNullOrEmpty(path) == false)
            {
                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 OnlineProcessing.finders.Values)
            {
                finder.ResetReferences();
            }
        }
        
        private static Finder GetFinder(IDevice dev, bool sample_insert)
        {
            string key = dev.Info.SerialNumber;
            if (sample_insert)
                key = $"{key}SI";
            
            if (OnlineProcessing.finders.ContainsKey(key) == false)
            {
                Finder new_finder = new Finder(dev, ReferenceWheelVersion.Auto, ExternalWhiteReferenceType.Zenith, Plugin.name)
                {
                    IdleTaskHandler = Plugin.host.ProcessEvents
                };

                if (sample_insert)
                    new_finder.ProbeType = new_finder.ProbeType == ProbeType.FinderSDStandard ? ProbeType.FinderSDInsert : ProbeType.FinderInsert;

                new_finder.WaitForExternalEmptyReference += () =>
                {
                    FinderReferenceDialog.Run(Plugin.host.MainWindow, FinderReferenceType.ExternalBlack);
                };
                
                new_finder.WaitForExternalWhiteReference += () =>
                {
                    FinderReferenceDialog.Run(Plugin.host.MainWindow,
                                                                             sample_insert 
                                                                                ? FinderReferenceType.ExternalInsert 
                                                                                : FinderReferenceType.ExternalWhiteZenith);
                };

                new_finder.UseCorrelationsReferenceChecks = false;
                OnlineProcessing.finders.Add(key, new_finder);
            }
            
            return OnlineProcessing.finders[key];
        }
        
        private static string GetReferencesPath()
        {
            if (string.IsNullOrEmpty(OnlineProcessing.ReferencesPath) && OnlineProcessing.NoReferencePath == false)
            {
                var 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;
        }
    }
}
