// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2021 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 Hiperscan.Extensions.ApoIdent.Widgets;
using Hiperscan.Extensions.ApoIdentCommon;
using Hiperscan.SGS;
using Hiperscan.Unix;

namespace Hiperscan.Extensions.ApoIdent
{
    public partial class ApoIdentApplication
    {
        private void InitCombinedFinder()
        {
            Console.WriteLine("Init combined Finder...");
            this.Finder?.Reset();
            this.Finder = new CombinedFinder(this.Config);
            this.Finder.DeviceModeChanged += this.OnDeviceModeChanged;
            this.Finder.AverageSet += this.OnAverageSet;
            this.Finder.VersionDetected += this.OnDeviceVersionDetected;
        }

        private void InitFinderEvents()
        {
            if (this.Finder?.Device == null)
                return;

            this.Finder.AddWaitForExternalBlackReferenceEvent(this.OnWaitForExternalBlackReference);
            this.Finder.AddWaitForExternalWhiteReferenceEvent(this.OnWaitForExternalWhiteReference);

            this.Finder.Warmup.WarmupStateChanged += this.OnWarmupStateChanged;
            this.Finder.Warmup.QuitRequested += this.OnWarmupQuitRequested;
        }


        private void OnWarmupQuitRequested(object sender, EventArgs e)
        {
            if (this.Finder.QuitRequested == true)
                this.Finder.Warmup.State = WarmupState.Finsihed;
        }


        private void OnWarmupStateChanged(object sender, EventArgs e)
        {
            switch (this.Finder.Warmup.State)
            {
                case WarmupState.Begin:
                    this.Update(ApoIdentApplicationState.ConnectionWarmupStart);
                    break;

                case WarmupState.Warming:
                    DeviceWarmup warmup = sender as DeviceWarmup;
                    this.Update(ApoIdentApplicationState.ConnectionWarmupProgress,
                                warmup.Fraction,
                                warmup.CurrentTemperature,
                                warmup.MinTemperature);
                    break;

                default:
                    break;
            }
        }

        private void OnInterruptingWarmupPressed(object sender, EventArgs e)
        {
            this.Update(ApoIdentApplicationState.ConnectDeviceWarmupInterrupted);
            if (this.DialogResponse == Gtk.ResponseType.Yes)
                this.RequestQuit();
            (sender as SplashScreen).Response = this.DialogResponse;
        }

        private void AddFinderInternalCalibrationEvents()
        {
            this.Finder.AddInternalCalibrationStartedEvent(this.OnFinderInternalCalibrationStarted);
            this.Finder.AddInternalCalibrationFinishedEvent(this.OnFinderInternalCalibrationFinished);
        }

        private void OnDeviceModeChanged(object sender, EventArgs e)
        {
            this.Update(ApoIdentApplicationState.DeviceStateChanged,(string)sender);
        }

        private void OnAverageSet(object sender, EventArgs e)
        {
            this.Update(ApoIdentApplicationState.DeviceAverageChanged);
        }

        private void OnDeviceAdded(DeviceList device_list, List<string> added_serials)
        {
            lock (this.Control.DeviceEventsSync)
            {
                if (this.Control.QuitRequested == true)
                    return;

                if (this.Control.ConnectionSuccess)
                    return;

                if (this.Control.IsDisconnecting)
                    return;

                if (this.Control.ConnectionIsInitializing == true)
                    return;
            }

            System.Threading.Tasks.Task.Run(() => this.InitConnection());
        }

        private void OnDeviceRemoved(DeviceList device_list, Dictionary<string,string> items)
        {
            this.RemoveDevice();
        }

        private void OnDeviceStateChanged(IDevice dev)
        {
            if (this.Finder.IsDeviceReady == false)
            {
                this.RemoveDevice();
            }
        }

        private void RemoveDevice()
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                lock (this.Control.DeviceEventsSync)
                {
                    if (this.Control.QuitRequested == true)
                        return;

                    if (this.Control.ConnectionSuccess == false)
                        return;

                    this.Control.ConnectionSuccess = false;
                    this.Control.IsDisconnecting = true;
                }

                lock (this.Control.Transaction)
                {
 
                    this.Finder?.Reset();
                    this.SubstanceManagement.ResetSelection();
                    this.InitSubstanceManagement();

                    string message = Catalog.GetString("Device is not connected or cannot be recognized. " +
                                                             "Please check in the Qickstep program if the device " +
                                                             "is recognized and connected. " +
                                                             "You can find these settings on the left side at the " +
                                                             "region called \"Spectrometer\".");


                    this.Control.Busy = false;
                    this.Update(ApoIdentApplicationState.ConnectionLost, message);
                    this.Control.IsDisconnecting = false;
                }
            });
        }

        private void OnFinderButtonStateChanged(FinderButtonStates state)
        {
            if (state == FinderButtonStates.AllowPolling)
                this.Finder?.FinderButton?.StartPolling();
            else
                this.Finder?.FinderButton?.StopPolling();
        }

        private void OnDeviceVersionDetected(object sender, EventArgs e)
        {
            CombinedFinder finder = sender as CombinedFinder;

            string value = String.Format("{0} | {1} | {2}",
                                         finder.ProductName,
                                         finder.Serial,
                                         finder.ConnectionType);
            this.Update(ApoIdentApplicationState.DeviceVersionDetected, value);
        }

        public  CombinedFinder Finder { get; private set; }
    }
}
