// Created with MonoDevelop
//
//    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.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Threading;

using Hiperscan.Common;
using Hiperscan.SGS.Benchtop.FinderSetup;
using Hiperscan.SGS.Common;
using Hiperscan.SGS.SerialInterface;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Spectroscopy.Math;
using Hiperscan.Spectroscopy.Processing;
using Hiperscan.Unix;

using Math = System.Math;

namespace Hiperscan.SGS.Benchtop
{
    public partial class AsyncStabilizedFinderX
    {
        public IDevice Device
        {
            get
            {
                return this.__finder.Device;
            }
        }

        public AcquisitionType AcquisitionRequest
        {
            get
            {
                return this.__acquisition_type;
            }
            set
            {
                this.__break_idle = true;
                this.__acquisition_type = value;

                StackFrame frame = new StackFrame(1, true);
                MethodBase method = frame.GetMethod();
                Console.WriteLine("{0}() is setting Finder AcquisitionRequest to {1}.", method.Name, value.ToString());
            }
        }

        public StateType State
        {
            get
            {
                StateType state = this.__state;

                StackFrame frame = new StackFrame(1, true);
                string method_name = frame.GetMethod().Name;
                frame = new StackFrame(2, true);
                string parent_method_name = frame.GetMethod()?.Name ?? "null";
                string state_debug_msg = string.Format("{0}() called from {1}() is reading Finder State/AcquisitionRequest: {2}/{3}.",
                                                       method_name, parent_method_name, state.ToString(), this.AcquisitionRequest.ToString());
                if (this.__last_state_debug_msg != state_debug_msg)
                {
                    this.__last_state_debug_msg = state_debug_msg;
                    Console.WriteLine(state_debug_msg);
                }

                return state;
            }
            set
            {
                lock (this)
                {
                    if (this.__ignore_state_changes)
                        return;

                    if (this.__state == value && this.__force_state_change == false)
                        return;

                    this.__force_state_change = false;
                    this.__break_idle = true;
                    this.__state = value;

                    StackFrame frame = new StackFrame(1, true);
                    string method_name = frame.GetMethod().Name;
                    frame = new StackFrame(2, true);
                    string parent_method_name = frame.GetMethod()?.Name ?? "null";
                    Console.WriteLine("{0}() called from {1}() is changing Finder State/AcquisitionRequest to {2}/{3}.",
                                      method_name, parent_method_name, value.ToString(), this.AcquisitionRequest.ToString());

                    this.NotifyStateChanged();
                }

                try
                {
                    this.Device.WaitForIdle(100);

                    switch (value)
                    {

                        case StateType.Idle:
                            lock (this)
                                this.Device.SetFinderStatus(FinderStatusType.Idle);
                            break;

                        case StateType.Init:
                        case StateType.WaitForLightSource:
                        case StateType.Busy:
                            lock (this)
                            {
                                this.Device.SetFinderStatus(FinderStatusType.Busy);
                            }
                            break;

                        case StateType.InternalWavelengthReference:
                        case StateType.InternalWhiteReference:
                        case StateType.DarkIntensity:
                        case StateType.AcquireExternalSpectrum:
                            break;

                        case StateType.Unknown:
                            lock (this)
                                this.Device.SetFinderStatus(FinderStatusType.Error);
                            break;

                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Cannot set Finder status: {0}", ex.ToString());
                }
            }
        }

        public LightSourceStateType LightSourceState
        {
            get { return this.__light_source_state; }
        }

        public bool StabilizationIsActive
        {
            get { return this.__stabilization_is_active; }
            set { this.__stabilization_is_active = value; }
        }

        public bool StabilizedLightSource
        {
            get { return this.__stabilized_light_source; }
            set { this.__stabilized_light_source = value; }
        }

        public bool CheckPlausibility
        {
            get { return this.__check_plausibility; }
            set { this.__check_plausibility = value; }
        }

        public bool TransflectanceMode
        {
            get { return this.__transflectance_mode; }
            set { this.__transflectance_mode = value; }
        }

        public bool RandomDelay
        {
            get { return this.__random_delay; }
            set { this.__random_delay = value; }
        }

        public ushort ReferenceAveraging
        {
            get
            {
                lock (this)
                    return this.__finder.ReferencingAverage;
            }
            set
            {
                lock (this)
                    this.__finder.ReferencingAverage = value;
            }
        }

        public string OutputDirPath
        {
            get
            {
                lock (this)
                    return this.__output_dir_path;
            }
            set
            {
                lock (this)
                {
                    this.__output_dir_path = value;
                    this.__finder.AutoSaveDirectory = value;
                }
            }
        }

        public bool AutoSaveSpectra
        {
            get
            {
                lock (this)
                    return this.__auto_save_spectra;
            }
            set
            {
                lock (this)
                {
                    this.__auto_save_spectra = value;
                }
            }
        }

        public string Comment
        {
            get
            {
                lock (this)
                    return this.__comment;
            }
            set
            {
                lock (this)
                    this.__comment = value;
            }
        }

        public ProbeType ProbeType
        {
            get
            {
                lock (this)
                    return this.__probe_type;
            }
            set
            {
                lock(this)
                    this.__probe_type = value;
            }
        }

        public ushort AverageCount
        {
            get
            {
                lock (this)
                    return this.__average_count;
            }
            set
            {
                lock (this)
                    this.__average_count = value;
            }
        }

        public string SeriesName
        {
            get
            {
                lock (this)
                    return this.__series_name;
            }
            set
            {
                lock (this)
                    this.__series_name = value;
            }
        }

        public bool AcquisitionSequenceRunning
        {
            get
            {
                lock (this)
                    return this.__acquisition_sequence_running;
            }
            set
            {
                lock (this)
                    this.__acquisition_sequence_running = value;
            }
        }

        public bool PlausibilityChecks
        {
            get
            {
                lock (this)
                    return this.__check_plausibility;
            }
            set
            {
                lock (this)
                    this.__check_plausibility = value;
            }
        }

        public bool AutoAcquisitionSequence
        {
            get
            {
                lock (this)
                    return this.__auto_acquisition_sequence;
            }
            set
            {
                lock (this)
                    this.__auto_acquisition_sequence = value;
            }
        }

        public int RegressionCount
        {
            get
            {
                lock (this)
                    return this.__regression_count;
            }
            set
            {
                lock (this)
                    this.__regression_count = value;
            }
        }

        public int ReferencingTimeoutMilliseconds
        {
            get
            {
                lock (this)
                    return 0;
            }
        }

        public int RecalibrationTimeoutMilliseconds
        {
            get
            {
                lock (this)
                    return 0;
            }
        }

        public bool AutoReferencing
        {
            get
            {
                lock (this)
                    return true;
            }

        }

        public RecalibrationMode RecalibrationMode
        {
            get
            {
                lock (this)
                    return RecalibrationMode.Always;
            }
        }

        public string AutoSaveDirectory
        {
            get
            {
                lock (this)
                    return this.__output_dir_path;
            }
        }

        public static double LightSourceWaitMinutes
        {
            get
            {
                return AsyncStabilizedFinderX.__light_source_wait_minutes;
            }
            set
            {
                AsyncStabilizedFinderX.__light_source_wait_minutes = value;
            }
        }

        public int IdleTimeoutMinutes
        {
            get
            {
                lock (this)
                    return 0;
            }
        }

        public Spectrum CurrentWhiteSpectrum
        {
            get
            {
                lock (this)
                    return this.__current_fix2glass_white_past;
            }
        }

        public Spectrum CurrentBlackSpectrum
        {
            get
            {
                lock (this)
                    return this.__current_fix2glass_black_past;
            }
        }

        public Spectrum CurrentTransflectanceReferenceSpectrum
        {
            get
            {
                lock (this)
                    return this.__current_transflectance_reference_spectrum;
            }
        }

        public Spectrum CurrentOxidSpectrum
        {
            get
            {
                lock (this)
                    return this.__current_fix2glass_oxide_past;
            }
        }

        public DateTime RecalibrationTimestamp
        {
            get
            {
                lock (this)
                    return this.__current_fix2glass_oxide_past != null ? this.__current_fix2glass_oxide_past.Timestamp : DateTime.MinValue;
            }
        }

        public double AutonomousTargetTemperature 
        { 
            get
            {
                return this.__finder.AutonomousTargetTemperature;
            }
        }

        public double SpectralResolution
        {
            get
            {
                lock (this)
                    return 10.0;
            }
        }

        public TemperatureInfo Temperatures
        {
            get
            {
                lock (this.__temperature_info)
                    return new TemperatureInfo(this.__temperature_info);
            }
        }

        public double Progress
        {
            get
            {
                return this.__progress;
            }
        }

        public double LightSourceEtaWaitSeconds
        {
            get
            {
                return this.__light_source_eta_wait_seconds;
            }
        }

        public bool FastLightSourceStabilization
        {
            get
            {
                lock (this)
                    return this.__fast_lightsource_stabilization;
            }
            set
            {
                lock (this)
                    this.__fast_lightsource_stabilization = value;
            }
        }
    }
}
