
// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2024. 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.Threading.Tasks;
using System.Runtime.Serialization;

using Hiperscan.Unix;
using Hiperscan.Spectroscopy;
using Hiperscan.Extensions.ReferenceCheck.Control.Enums;
using Hiperscan.Extensions.ReferenceCheck.Control.GuiUpdate;

namespace Hiperscan.Extensions.ReferenceCheck.Control.Acquisition
{
    [Serializable]
    [DataContract]
    public class CalibrationSession : IComparable<CalibrationSession>
    {
        public event UpdateGuiHandler UpdateGuiNeeded = null;

        public CalibrationSession(int id, int number_of_acquisitions)
        {
            this.Id = id;
            this.CalculateTimeOut(number_of_acquisitions);
        }

        private void CalculateTimeOut(int number_of_measurements)
        {
            this.TimeOutTimeMinutes = (int)(0.5 * number_of_measurements + 1);
        }

        public void StartTimer()
        {
            this.AcquisitionTime = DateTime.Now;
            Task.Run(() => this.DoStartTimer());
        }

        private void DoStartTimer()
        {
            this.TimerIsRunning = true;
            this.EndTimeStamp = DateTime.Now.AddMinutes(this.TimeOutTimeMinutes);

            for (; ; )
            {
                lock (this.TimerSync)
                {
                    this.TimerIsRunning = true;
                    if (this.TimerIsRunning == false)
                        break;

                    bool leave = this.IsTimeOut;

                    UpdateArgs arg = new UpdateArgs();
                    arg.ViewType = ViewTypes.Acquisition;
                    arg.UpdateCatecory = UpdateCategory.Often;
                    this.UpdateGuiNeeded?.Invoke(arg);

                    if (leave)
                        break;
                }

                System.Threading.Thread.Sleep(333);
            }
        }

        public void StopTimer()
        {
            lock (this.TimerSync)
            {
                this.TimerIsRunning = false;

                UpdateArgs arg = new UpdateArgs();
                arg.ViewType = ViewTypes.Acquisition;
                arg.UpdateCatecory = UpdateCategory.Often;
                this.UpdateGuiNeeded?.Invoke(arg);
            }
        }

        public string GetAcqquisitionTime()
        {
            if (this.TimerIsRunning == false)
                return String.Empty;

            if (this.IsTimeOut)
                return Catalog.GetString("00:00 min");

            TimeSpan diff = this.EndTimeStamp - DateTime.Now;
            return String.Format(Catalog.GetString("{0:d2}:{1:d2} min"),
                                 diff.Minutes,
                                 diff.Seconds % 60);
        }

        public bool IsTimeOut
        {
            get
            {
                return DateTime.Now > this.EndTimeStamp;
            }
        }

        public int CompareTo(CalibrationSession other)
        {
            return this.Id.CompareTo(other.Id);
        }

        [DataMember]
        public  bool HasInternalCalibration { get; set; } = false;
        [DataMember]
        public bool IsInternalRecalibrating { get; set; } = false;

        [DataMember]
        private DateTime EndTimeStamp { get; set; }
        [DataMember]
        private bool TimerIsRunning { get; set; } = false;
        [DataMember]
        public int TimeOutTimeMinutes { get; private set; } = 20;
        [DataMember]
        private object TimerSync { get; set; } = new object();

        [DataMember]
        public Spectrum DarkSpectrum { get; set; }
        [DataMember]
        public Spectrum WhiteSpectrum { get; set; }
        [DataMember]
        public Spectrum OxidSpectrum { get; set; }

        [DataMember]
        public int Id { get; private set; }
        [DataMember]
        public DateTime AcquisitionTime { get; set; }
    }
}
