// 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.IO;
using System.Threading;
using Hiperscan.Common;
using Hiperscan.SGS.Common;

namespace Hiperscan.SGS.Benchtop.FinderButtonPolling
{
    public partial class FinderButton<T> : Polling where T : FinderButtonStateTemplate, new ()
    {
        public FinderButton()
        {
            this.PollingTimeIntervallMilliSeconds = 250;
            this.ConsoleWriter = Console.Out;

            this.FinderButtonState = new T();
            this.FinderButtonState.AllConditionsStateChanged += this.OnFinderButtonStateChanged;
        }

        public void Init(IDevice device)
        {
            this.Device = device;
            if (this.Device == null)
            {
                this.Reset();
                return;
            }


            //TODO #38109
            this.FinderButtonState.DeviceExists.IsActive = true;

            if ((string)Environment.GetEnvironmentVariable("QS_TEST") != "1")
            {
                if ((this.Device.FinderVersion.Board == 0 && this.Device.FinderVersion.Casing == 0) ||
                    (this.Device.FinderVersion.Board == 6) ||
                    (this.Device.FinderVersion.Board == 7))
                {
                    this.FinderButtonState.HardwareSupport.IsActive = true;
                    this.AllowRestartPolling();
                }
            }
        }

        public void Reset()
        {
            this.FinderButtonState.Reset();
            this.WaitForPollingEnd();
            this.Device = null;
        }

        private void OnFinderButtonStateChanged(object sender,  EventArgs e)
        {
            T state = sender as T;

            if (state.ArePollingConditionsActive)
                this.StartPolling();
            else
                this.StopPolling();
        }

        protected override void BeforeStartRunning()
        {
            this.DebouncePressEvent();
            Console.WriteLine("FinderButton start polling...");
            this.SwitchLight(true);
        }

        protected override void AfterFinishRunning()
        {
            this.DebouncePressEvent();
            this.SwitchLight(false);
            Console.WriteLine("FinderButton polling stopped.");
        }

        protected override void ExecutePollingEvent()
        {
            System.Threading.Tasks.Task.Run(() => this.EnterMeasureCycle(true));
        }

        public bool IsButtonPressed()
        {
            lock (this.DeviceSync)
            {
                try
                {
                    this.ConsoleActive = false;
                    this.StateNotification = false;

                    bool is_pressed = this.Device.FinderButtonPressed();
                    this.StateNotification = true;
                    this.ConsoleActive = true;

                    return is_pressed;
                }
                catch (Exception ex)
                {
                    this.StateNotification = true;
                    this.ConsoleActive = true;
                    Console.WriteLine("Error while activationg finder button: {0}", ex);

                    return false;
                }
            }
        }

        private void SwitchLight(bool on)
        {
            lock (this.DeviceSync)
            {

                this.ConsoleActive = false;

                for (int i = 0; i < 5; i++)
                {
                    try
                    {
                        this.Device.WaitForIdle(1000);
                        Spectrometer.State state = this.Device.GetState();

                        if (state != Spectrometer.State.Idle)
                            throw new Exception(String.Format("Device has no state 'Idle'. State is: {0}", state));

                        this.Device.SwitchFinderStatusLED(on);
                        this.ConsoleActive = true;
                        break;
                    }
                    catch (Exception ex)
                    {
                        if (i == 4)
                        {
                            this.ConsoleActive = true;
                            Console.WriteLine("Cannot activate finder button: {0}", ex);
                        }
                    }
                }
            }
        }

        private void DebouncePressEvent()
        {
            for (; ; )
            {
                if (this.IsButtonPressed() == false)
                    break;

                System.Threading.Thread.Sleep(this.WaitTimeMilliSeconds);
            }
        }

        private bool StateNotification
        {
            set
            {
                try
                {
                    this.Device.StateNotification = value;
                }
#pragma warning disable RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist
                catch (Exception) 
                {
                }
#pragma warning restore RECS0022 // catch-Klausel, die System.Exception abfängt und keinen Text aufweist
            }
        }

        private bool ConsoleActive
        {
            set
            {
                //UNDO
                return;

                if (value == false)
                    Console.SetOut(TextWriter.Null);
                else
                    Console.SetOut(this.ConsoleWriter);
            }
        }

        private IDevice Device { get; set; } = null;
        private object DeviceSync { get; set; } = new object();

        public T FinderButtonState { get; private set; }
        private TextWriter ConsoleWriter { get; set; }
    }
}
