// Created with MonoDevelop
//
//    Copyright (C) 2009 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 Hiperscan.Spectroscopy;
using Hiperscan.Unix;


namespace Hiperscan.SGS.Common
{

    public static partial class Spectrometer
    {
        
        public enum ReferenceSpectrumType : int
        {
            None   = 2,
            File   = 1,
            Record = 0
        }
        
        public enum DarkIntensityType : int
        {
            None,
            File,
            Record,
            Specify
        }
        
        public enum StreamType : int
        {
            Continuous,
            Timed
        }

        public enum TriggerType : byte
        {
            Software = 0,   // immidiately start sampling with actual average cycles 
            Edge = 1,       // start sampling at rising trigger edge with actual average cycles 
            Gate = 2,       // sample while trigger is at HI level report back effective sampled average cycles
        }

        public class Config
        {
            private ushort  average;
            private bool    auto_timeout;
            private int     timeout;
            private string  name;
            private IDevice device;

            private Spectrum      reference_spectrum;
            private DarkIntensity dark_intensity;
            
            private WavelengthCorrection wavelength_correction;
            private DataSet              adc_correction;

            public Config(IDevice device)
            {
                this.IsInitialized = false;

                this.device = device;
                
                this.Collect = false;
                this.auto_timeout = true;
                this.average      = 500;
                this.Samples      = 5000;
                this.timeout      = this.CalculateAutoTimeout();
                this.TimedSpan    = 0;
                this.TimedCount   = 0;
                
                this.QuickAverage = 15;
                this.QuickSamples = 5000;
                
                this.name           = string.Empty;
                this.DefaultComment = string.Empty;
                
                this.ReferenceSpectrumType = ReferenceSpectrumType.None;
                this.DarkIntensityType     = DarkIntensityType.None;
                this.StreamType            = StreamType.Timed;
                
                this.dark_intensity        = new DarkIntensity(0.0, 0.0);
                this.wavelength_correction = null;
                this.adc_correction        = null;
                
                this.TriggerDelay  = 0;
                this.TriggerMode   = TriggerType.Software;
                this.TriggerInvert = false;
                this.LambdaCenter  = 1450.0;
                this.Amplitude     = 12.0;
                this.Grid          = 1600;
                this.Deviation     = 15.0;

                this.UserData = null;
            }
            

            public Config(Config config)
            {
                this.IsInitialized = true;
                
                this.device       = config.device;
                this.Collect      = config.Collect;
                this.auto_timeout = config.AutoTimeout;
                this.Amplitude    = config.Amplitude;
                this.average      = config.Average;
                this.Deviation    = config.Deviation;
                this.Grid         = config.Grid;
                this.Samples      = config.Samples;
                this.Frequency    = config.Frequency;
                
                this.QuickAverage = config.QuickAverage;
                this.QuickSamples = config.QuickSamples;
                
                this.adc_correction = config.AdcCorrection;
                
                this.TriggerDelay  = config.TriggerDelay;
                this.TriggerMode  = config.TriggerMode;
                this.TriggerInvert = config.TriggerInvert;
                this.LambdaCenter  = config.LambdaCenter;
                this.LambdaMin     = config.LambdaMin;
                this.LambdaMax     = config.LambdaMax;

                this.timeout    = config.Timeout;
                this.TimedSpan  = config.TimedSpan;
                this.TimedCount = config.TimedCount;
                
                this.name           = config.Name;
                this.DefaultComment = config.DefaultComment;
                
                this.ReferenceSpectrumType = config.ReferenceSpectrumType;
                this.reference_spectrum    = config.ReferenceSpectrum;
                this.StreamType            = config.StreamType;

                this.DarkIntensityType = config.DarkIntensityType;
                this.dark_intensity    = new DarkIntensity(config.DarkIntensity);
                
                this.wavelength_correction = config.WavelengthCorrection;
                this.adc_correction        = config.AdcCorrection;
                
                this.UserData = config.UserData;
            }

            internal bool IsInitialized { get; set; }

            public bool IsValid
            {
                get
                {
                    if (this.Grid < 500 || this.Grid > 3000 ||
                        this.LambdaCenter < 900 || this.LambdaCenter > 2500 ||
                        this.Amplitude < 5.0 || this.Amplitude > 25.0 ||
                        this.Deviation < 5.0 || this.Deviation > 45.0)
                    {
                        Console.WriteLine("Invalid configuation detected:");
                        Console.WriteLine("\tsamples: " + this.Samples);
                        Console.WriteLine("\tsample_rate: " + this.SampleRate);
                        Console.WriteLine("\tgrid: " + this.Grid);
                        Console.WriteLine("\tlambda_min: " + this.LambdaMin);
                        Console.WriteLine("\tlambda_center: " + this.LambdaCenter);
                        Console.WriteLine("\tlambda_max: " + this.LambdaMax);
                        Console.WriteLine("\tamplitude: " + this.Amplitude);
                        Console.WriteLine("\tdeviation: " + this.Deviation);
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            
            private int CalculateAutoTimeout()
            {
                return (int)(2000.0 + 32.0 * (double)this.Average);
            }

            public string Name
            {
                get
                {
                    if (string.IsNullOrEmpty(this.name))
                        return this.device.Info.SerialNumber;
                    else
                        return this.name;
                }
                set { this.name = value; }
            }

            public string DefaultComment { get; set; }

            public bool HasDefaultComment
            {
                get { return !string.IsNullOrEmpty(this.DefaultComment); }
            }
            
            public int Timeout
            {
                get    
                {
                    return this.timeout;  
                }
                set
                {
                    if (this.AutoTimeout == false)
                        this.timeout = value;
                }
            }

            public ulong TimedSpan { get; set; }

            public ulong TimedCount { get; set; }

            public ushort Samples { get; set; }

            public ushort Average
            {
                get    
                { 
                    return this.average;
                }
                set
                {
                    this.average = value;
                    
                    if (this.AutoTimeout)
                        this.timeout = this.CalculateAutoTimeout();
                }
            }

            public ushort QuickSamples { get; set; }

            public ushort QuickAverage { get; set; }

            public ushort TriggerDelay { get; set; }

            public ushort Grid { get; set; }

            public double LambdaMin { get; set; }

            public double LambdaCenter { get; set; }

            public double LambdaMax { get; set; }

            public double Amplitude { get; set; }

            public double Frequency { get; set; }

            public double Deviation { get; set; }

            public double SampleRate { get; set; }

            internal bool Collect { get; set; }

            public TriggerType TriggerMode { get; set; }

            public bool TriggerInvert { get; set; }

            public bool AutoTimeout
            {
                get
                { 
                    return this.auto_timeout;
                }
                set
                {
                    this.auto_timeout = value;

                    if (value)
                        this.timeout = this.CalculateAutoTimeout();
                }    
            }

            public ReferenceSpectrumType ReferenceSpectrumType { get; set; }

            public DarkIntensityType DarkIntensityType { get; set; }

            public StreamType StreamType { get; set; }

            public Spectrum ReferenceSpectrum
            {
                get
                {
                    return this.reference_spectrum;
                }
                set
                {
                    this.reference_spectrum = value;
                    if (this.reference_spectrum != null)
                    {
                        this.reference_spectrum.Label = Catalog.GetString("Current background spectrum");
                        this.reference_spectrum.Id    = "8background" + this.reference_spectrum.GetHashCode();

                        this.reference_spectrum.DarkIntensity = new DarkIntensity(this.DarkIntensity);
                        if (this.HasWavelengthCorrection)
                            this.reference_spectrum.WavelengthCorrection = this.WavelengthCorrection;
                        if (this.HasAdcCorrection)
                            this.reference_spectrum.AdcCorrection = this.AdcCorrection;
                    }
                }
            }
            
            public bool HasReferenceSpectrum
            {
                get    { return this.reference_spectrum != null; }
            }
            
            public bool HasWavelengthCorrection
            {
                get    { return this.wavelength_correction != null; }
            }
            
            public bool HasAdcCorrection
            {
                get { return this.adc_correction != null; }
            }

            public DarkIntensity DarkIntensity
            {
                get
                { 
                    return this.dark_intensity; 
                }
                set    
                {
                    this.dark_intensity = value;
                    
                    if (this.HasReferenceSpectrum)
                        this.ReferenceSpectrum.DarkIntensity = new DarkIntensity(value);
                }
            }

            public WavelengthCorrection WavelengthCorrection
            {
                get
                { 
                    return this.wavelength_correction;
                }
                set 
                { 
                    this.wavelength_correction = value; 
                    
                    if (this.HasReferenceSpectrum)
                        this.ReferenceSpectrum.WavelengthCorrection = this.WavelengthCorrection;
                }
            }
            
            public DataSet AdcCorrection
            {
                get 
                { 
                    return this.adc_correction; 
                }
                set 
                { 
                    this.adc_correction = value; 
                    
                    if (this.HasReferenceSpectrum)
                        this.ReferenceSpectrum.AdcCorrection = this.AdcCorrection;
                }
            }

            public object UserData { get; set; }
        }
    }
}
