// 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
{

	public abstract partial class Device
	{
		
		public enum BackgroundSpectrumType : int
		{
			None   = 2,
			File   = 1,
			Record = 0
		}
		
		public enum DarkIntensityType : int
		{
			None,
			File,
			Record,
			Specify
		}
		
		public enum StreamType : int
		{
			Continuous,
			Timed
		}
		
		public class Config
		{
			private bool is_initialized;
			
			private ushort samples, trigger_delay, grid, average;
			private ushort quick_samples, quick_average;
			private double lambda_min, lambda_center, lambda_max;
			private double amplitude, frequency, deviation, sample_rate;
			private bool   collect;
			private bool   auto_timeout;
			private int    timeout;
			private ulong  timed_span;
			private ulong  timed_count;
			private string name;
			private string default_comment;
			private object user_data;
			
			private Device device;

			private BackgroundSpectrumType bg_type;
			private DarkIntensityType      di_type;
			private StreamType             stream_type;
			
			private Spectrum      background_spectrum;
			private DarkIntensity dark_intensity;
			
			private WavelengthCorrection wavelength_correction;
			private DataSet              adc_correction;
			
			public Config(Device device)
			{
				this.is_initialized = false;

				this.device = device;
				
				this.collect      = false;
				this.auto_timeout = true;
				this.average      = 500;
				this.samples      = 5000;
				this.timeout      = this.CalculateAutoTimeout();
				this.timed_span   = 0;
				this.timed_count  = 0;
				
				this.quick_average = 15;
				this.quick_samples = 5000;
				
				this.name            = string.Empty;
				this.default_comment = string.Empty;
				
				this.bg_type     = BackgroundSpectrumType.None;
				this.di_type     = DarkIntensityType.None;
				this.stream_type = StreamType.Timed;
				
				this.dark_intensity = new DarkIntensity(0f, 0f);
				this.wavelength_correction = null;
				this.adc_correction        = null;
				
				this.trigger_delay = 0;
				this.lambda_center = 1450f;
				this.amplitude = 12f;
				this.grid = 1600;
				this.deviation = 15f;
				
				this.user_data = null;
			}
			
			public Config(Config config)
			{
				this.is_initialized = 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.quick_average = config.QuickAverage;
				this.quick_samples = config.QuickSamples;
				
				this.adc_correction = config.AdcCorrection;
				
				this.trigger_delay = config.TriggerDelay;
				this.lambda_center = config.LambdaCenter;
				this.lambda_min    = config.LambdaMin;
				this.lambda_max    = config.LambdaMax;
				
				this.timeout     = config.Timeout;
				this.timed_span  = config.TimedSpan;
				this.timed_count = config.TimedCount;
				
				this.name            = config.Name;
				this.default_comment = config.DefaultComment;
				
				this.bg_type             = config.BackgroundSpectrumType;
				this.background_spectrum = config.BackgroundSpectrum;
				this.stream_type         = config.StreamType;

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

			internal bool IsInitialized
			{
				get { return this.is_initialized;  }
				set { this.is_initialized = value; }
			}

			public bool IsValid
			{
				get
				{
					if (this.grid          < 500 || this.grid          > 3000 ||
					    this.lambda_center < 900 || this.lambda_center > 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.sample_rate);
						Console.WriteLine("\tgrid: " + this.grid);
						Console.WriteLine("\tlambda_min: " + this.lambda_min);
						Console.WriteLine("\tlambda_center: " + this.lambda_center);
						Console.WriteLine("\tlambda_max: " + this.lambda_max);
						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 { return this.default_comment;  }
				set { this.default_comment = value; }
			}
			
			public bool HasDefaultComment
			{
				get { return !string.IsNullOrEmpty(this.default_comment); }
			}
			
			public int Timeout
			{
				get	{ return this.timeout;  }
				set
				{
					if (!this.AutoTimeout)
						this.timeout = value;
				}
			}
			
			public ulong TimedSpan
			{
				get	{ return this.timed_span;  }
				set { this.timed_span = value; }
			}
			
			public ulong TimedCount
			{
				get	{ return this.timed_count;  }
				set { this.timed_count = value; }
			}
			
			public ushort Samples
			{
				get	{ return this.samples;  }
				set { this.samples = value; }
			}
			
			public ushort Average
			{
				get	{ return this.average;  }
				set
				{
					this.average = value;
					
					if (this.AutoTimeout)
						this.timeout = this.CalculateAutoTimeout();
				}
			}
				
			public ushort QuickSamples
			{
				get	{ return this.quick_samples;  }
				set { this.quick_samples = value; }
			}
			
			public ushort QuickAverage
			{
				get	{ return this.quick_average;  }
				set { this.quick_average = value; }
			}
				
			public ushort TriggerDelay
			{
				get { return this.trigger_delay;  }
				set { this.trigger_delay = value; }
			}

			public ushort Grid
			{
				get { return this.grid;  }
				set { this.grid = value; }
			}
			
			public double LambdaMin
			{
				get { return this.lambda_min;  }
				set { this.lambda_min = value; }
			}
			
			public double LambdaCenter
			{
				get { return this.lambda_center;  }
				set { this.lambda_center = value; }
			}
			
			public double LambdaMax
			{
				get { return this.lambda_max;  }
				set { this.lambda_max = value; }
			}
			
			public double Amplitude
			{
				get { return this.amplitude;  }
				set { this.amplitude = value; }
			}
			
			public double Frequency
			{
				get { return this.frequency;  }
				set { this.frequency = value; }
			}

			public double Deviation
			{
				get { return this.deviation;  }
				set { this.deviation = value; }
			}
			
			public double SampleRate
			{
				get	{ return this.sample_rate;  }
				set { this.sample_rate = value; }
			}
			
			internal bool Collect
			{
				get	{ return this.collect;  }
				set { this.collect = value; }
			}
			
			public bool AutoTimeout
			{
				get	{ return this.auto_timeout;  }
				set
				{
					this.auto_timeout = value;

					if (value)
						this.timeout = this.CalculateAutoTimeout();
				}	
			}
			
			public BackgroundSpectrumType BackgroundSpectrumType
			{
				get { return this.bg_type;  }
				set	{ this.bg_type = value;	}
			}
			
			public DarkIntensityType DarkIntensityType
			{
				get { return this.di_type;  }
				set { this.di_type = value;	}
			}
			
			public StreamType StreamType
			{
				get	{ return this.stream_type;  }
				set	{ this.stream_type = value; }
			}
			
			public Spectrum BackgroundSpectrum
			{
				get
				{
					return this.background_spectrum;
				}
				set
				{
					this.background_spectrum = value;
					if (this.background_spectrum != null)
					{
						this.background_spectrum.Label = Catalog.GetString("Current background spectrum");
						this.background_spectrum.Id    = "8background" + this.background_spectrum.GetHashCode();

						this.background_spectrum.DarkIntensity = new DarkIntensity(this.DarkIntensity);
						if (this.HasWavelengthCorrection)
							this.background_spectrum.WavelengthCorrection = this.WavelengthCorrection;
						if (this.HasAdcCorrection)
							this.background_spectrum.AdcCorrection = this.AdcCorrection;
					}
				}
			}
			
			public bool HasBackgroundSpectrum
			{
				get	{ return this.background_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.HasBackgroundSpectrum)
						this.BackgroundSpectrum.DarkIntensity = new DarkIntensity(value);
				}
			}

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

			public object UserData
			{
				get { return this.user_data;  }
				set	{ this.user_data = value; }
			}
		}
	}
}
