// 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 System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Drawing;
using System.Linq;

using Hiperscan.Spectroscopy;
using Hiperscan.Unix;


namespace Hiperscan.FileIO
{

    public static partial class CSV
	{
		public const string SampleFileNameRegex 	= @"^[0-9A-Z]+_(([A-Z]{1,4})|([A-Z]{1}\d{7}))_\d+\.csv$"; // changed by TOS 2016-03-03
		public const string CustomerFileNameRegex 	= @"^.+__.+__.+\.csv$";

		private static volatile bool ignore_correction = false;
		private static volatile uint open_id = 0;
		
        public static readonly CultureInfo DEFAULT_CULTURE = CultureInfo.CurrentCulture;

		public static Spectrum Read(string fname)
		{
			return CSV.Read(fname, -1);
		}

		public static Spectrum Read(string fname, int count)
		{
            using (FileStream stream = new FileStream(fname, FileMode.Open, FileAccess.Read))
            {	
                Spectrum spectrum = CSV._Read(stream, count);
                spectrum.FileInfo = new FileInfo(fname);
                spectrum.Id = string.Format("0_{0}_{1}", (open_id++).ToString("D9"), spectrum.FileInfo.FullName);
                if (string.IsNullOrEmpty(spectrum.Label))
                {
                    spectrum.Label = spectrum.FileInfo.Name;
                    spectrum.DefaultLabel = true;
                }
                return spectrum;
            }
		}
		
		public static Spectrum Read(Stream stream)
		{
			Spectrum spectrum = CSV._Read(stream, -1);
			spectrum.FileInfo = null;
			spectrum.Id = "0_stream_input";
			return spectrum;
		}

		private static Spectrum _Read(Stream stream, int count)
		{
			List<double> raw_lambda     = new List<double>();
			List<double> raw_intensity  = new List<double>();
			List<double> raw_absorbance = new List<double>();

			Spectrum   spectrum   = new Spectrum(WavelengthLimits.DefaultWavelengthLimits);
			string     label      = string.Empty;
			Color      color      = Color.Empty;
			LineStyle  line_style = LineStyle.Solid;
			float      line_width = 0f;
			List<uint> add_data   = new List<uint>();
			
			// the separator regex and culture can be changed while parsing the header!
			Regex regex = new Regex(CSV.Parser.DefaultSeparator);
			CultureInfo current_culture = CSV.DEFAULT_CULTURE;
				
			string line;
			int skipped = 0;
			int line_number = 0;
			
			if (count < 1)
			{
				count = -1;
			}
			else
			{
				spectrum.IsComplete = false;
			}

			using (StreamReader reader = new StreamReader(stream))
			{
				while ((line = reader.ReadLine()) != null &&
				       (line_number - skipped)    != count)
				{
					if (string.IsNullOrEmpty(line))
						continue;

					++line_number;
					
					string[] s = regex.Split(line);

					if (s.Length > 0 && s[0].StartsWith("#"))
					{
						++skipped;

						string[] split_line = line.Split('=');
						
						// skip custom or empty comments
						if (split_line.Length < 2)
							continue;

						string parser_type = split_line[0].Remove(0, 1).Trim();
						switch (parser_type)
						{
							
						case Parser.Culture:
							string new_culture = (string)CSV.ParseLine(line, Parser.Culture, current_culture);
							current_culture = new CultureInfo(new_culture);
							regex = new Regex(current_culture.TextInfo.ListSeparator);
							break;
							
						case Parser.SpectrumTime:
							spectrum.Timestamp = 
								(DateTime)CSV.ParseLine(line, Parser.SpectrumTime, current_culture);
							break;
							
						case Parser.DarkIntensity:
							spectrum.DarkIntensity.SetIntensity((double)CSV.ParseLine(line, Parser.DarkIntensity, current_culture));
							break;

						case Parser.DarkIntensitySigma:
							spectrum.DarkIntensity.SetSigma((double)CSV.ParseLine(line, Parser.DarkIntensitySigma, current_culture));
							break;
							
						case Parser.DarkIntensityTime:
							spectrum.DarkIntensity.SetDateTime((DateTime)CSV.ParseLine(line, Parser.DarkIntensityTime, current_culture));
							break;
							
						case Parser.WavelengthCorrection:
							if (CSV.ignore_correction)
								continue;
							spectrum.WavelengthCorrection = 
							     (WavelengthCorrection)CSV.ParseLine(line, Parser.WavelengthCorrection, current_culture);
							break;
							
						case Parser.WavelengthLimits:
							if (CSV.ignore_correction)
								continue;
							spectrum.WavelengthLimits = 
							     (WavelengthLimits)CSV.ParseLine(line, Parser.WavelengthLimits, current_culture);
							break;
							
						case Parser.AdcCorrection:
							if (CSV.ignore_correction)
								continue;
							spectrum.AdcCorrection =
								(DataSet)CSV.ParseLine(line, Parser.AdcCorrection, current_culture);
							break;
							
						case Parser.WavelengthCorrectionTime:
							if (spectrum.HasWavelengthCorrection)
							{
								spectrum.WavelengthCorrection.DateTime = 
								     (DateTime)CSV.ParseLine(line, Parser.WavelengthCorrectionTime, current_culture);
							}
							break;
							
						case Parser.LinearDistortion:
							if (CSV.ignore_correction)
								continue;
							spectrum.LinearDistortion =
							     (LinearDistortion)CSV.ParseLine(line, Parser.LinearDistortion, current_culture);
							break;
							
						case Parser.LinearDistortionTime:
							if (spectrum.HasLinearDistortion)
							{
								spectrum.LinearDistortion.DateTime = 
								    (DateTime)CSV.ParseLine(line, Parser.LinearDistortionTime, current_culture);
							}
							break;

						case Parser.LimitBandwidth:
							spectrum.LimitBandwidth = 
								(bool)CSV.ParseLine(line, Parser.LimitBandwidth, current_culture);
							break;

						case Parser._LimitWavelength:
							spectrum.LimitBandwidth = 
								(bool)CSV.ParseLine(line, Parser._LimitWavelength, current_culture);
							break;
							
						case Parser.SerialNumber:
							spectrum.Serial = 
							    (string)CSV.ParseLine(line, Parser.SerialNumber, current_culture);
							break;
							
						case Parser.FirmwareVersion:
							spectrum.FirmwareVersion = 
							    (string)CSV.ParseLine(line, Parser.FirmwareVersion, current_culture);
							break;

						case Parser.FirmwareRevision:
							spectrum.FirmwareRevision = 
								(string)CSV.ParseLine(line, Parser.FirmwareRevision, current_culture);
							break;
							
						case Parser.LutTimestamp:
							spectrum.LutTimestamp = 
							    (string)CSV.ParseLine(line, Parser.LutTimestamp, current_culture);
							break;
							
						case Parser.HardwareVersionInfo:
							spectrum.HardwareInfo = 
								(byte[])CSV.ParseLine(line, Parser.HardwareVersionInfo, current_culture);
							break;
							
						case Parser.AverageCount:
							spectrum.AverageCount = 
							    (int)CSV.ParseLine(line, Parser.AverageCount, current_culture);
							break;
							
						case Parser.SpectralResolution:
							spectrum.SpectralResolution = 
							    (double)CSV.ParseLine(line, Parser.SpectralResolution, current_culture);
							break;

						case Parser.SpectrumType:
							spectrum.SpectrumType = 
								(SpectrumType)CSV.ParseLine(line, Parser.SpectrumType, current_culture);
							break;

						case Parser.ProbeType:
							spectrum.ProbeType =
								(ProbeType)CSV.ParseLine(line, Parser.ProbeType, current_culture);
							break;

						case Parser.Creator:
							spectrum.Creator = 
								(string)CSV.ParseLine(line, Parser.Creator, current_culture);
							break;
							
						case Parser.Label:
							label = (string)CSV.ParseLine(line, Parser.Label, current_culture);
							break;
							
						case Parser.LineColor:
							color = (Color)CSV.ParseLine(line, Parser.LineColor, current_culture);
							break;
							
						case Parser.LineStyle:
							line_style = (LineStyle)CSV.ParseLine(line, Parser.LineStyle, current_culture);
							break;
							
						case Parser.LineWidth:
							line_width = (float)CSV.ParseLine(line, Parser.LineWidth, current_culture);
							break;
							
						case Parser.Comment:
							spectrum.Comment += 
								(string)CSV.ParseLine(line, CSV.Parser.Comment, current_culture);
							break;
							
						case Parser.AddData:
							add_data.Add((uint)CSV.ParseLine(line, CSV.Parser.AddData, current_culture));
							break;
							
						default:
							// skip unknown header entries
							continue;
							
						}
					}
					else
					{
						try
						{
							raw_lambda.Add(Double.Parse(s[0],
							                            NumberStyles.AllowDecimalPoint|
							                            NumberStyles.AllowExponent,
							                            current_culture)
							               );

							raw_intensity.Add(Double.Parse(s[1],
							                               NumberStyles.AllowDecimalPoint|
							                               NumberStyles.AllowExponent,
							                               current_culture)
							                  );

							// read absorbance if there is a third column
							if (s.Length > 2)
							{
								raw_absorbance.Add(Double.Parse(s[2],
								                                NumberStyles.AllowDecimalPoint|
								                                NumberStyles.AllowExponent|
								                                NumberStyles.AllowLeadingSign,
								                                current_culture)
								                   );
							}		
						}
						catch (Exception exx)
						{
							++skipped;
						
							// ignore blank lines
							if (string.IsNullOrEmpty(line.Trim()))
								continue;

							if (line[0] == ' ')
							{
								Console.WriteLine("Skipping missformed line: " + line);
								continue;
							}

							if (line_number > Parser.MaxHeaderLines || !line.StartsWith("#"))
								throw new Exception(Catalog.GetString("Cannot read csv file: Missformed data section") + 
								                    " (" + exx.Message + ").");
						
						}
					}
				}
			}
			
			spectrum.CultureInfo = current_culture;
		
			if (spectrum.Comment.EndsWith("\n"))
				spectrum.Comment.Remove(spectrum.Comment.Length-1);
			
//			Console.WriteLine("Read " + lambda.Count + " data sets from file (" 
//			                  + skipped + " lines skipped/parsed):\n\t'"
//			                  + fname   + "'");

			spectrum.RawIntensity = new DataSet(raw_lambda, raw_intensity);
			if (raw_absorbance.Count == raw_lambda.Count)
			{
				if (!spectrum.HasDarkIntensity)
					throw new Exception(Catalog.GetString("Absorbance spectra have to define Dark Intensity values."));
				double di = spectrum.DarkIntensity.Intensity;
				DataSet raw_absorbance_ds = new DataSet(raw_lambda, raw_absorbance);
				DataSet raw_intensity_di_ds = spectrum.RawIntensity - new DataSet.Operand(0.0, di);
				
				// negative intensity is not defined, zero intensity would be infinite absorbance
				for (int ix=0; ix < raw_intensity_di_ds.Count; ++ix)
				{
					if (raw_intensity_di_ds.Y[ix] < 1e-10)
						raw_intensity_di_ds.Y[ix] = 1e-10;
				}
				
				DataSet raw_background_di_ds = DataSet.InverseAbsorbance(raw_intensity_di_ds, raw_absorbance_ds);
				DataSet raw_background_ds = raw_background_di_ds + di;
				Spectrum background = new Spectrum(raw_background_ds, spectrum.WavelengthLimits);
				background.WavelengthCorrection = spectrum.WavelengthCorrection;
				background.AdcCorrection = spectrum.AdcCorrection;
				spectrum.Background = background;
				
				foreach (double y in spectrum.Absorbance.Y)
				{
					if (double.IsInfinity(y))
						throw new Exception(Catalog.GetString("Absorbance contains infinite values."));
					if (double.IsNaN(y))
						throw new Exception(Catalog.GetString("Absorbance contains invalid values."));
				}
			}

			if (!string.IsNullOrEmpty(label))
				spectrum.Label = label;
			
			if (color != Color.Empty)
				spectrum.Color = color;
			
			if (line_style != LineStyle.Solid)
				spectrum.LineStyle = line_style;
			
			if (line_width > 0f)
				spectrum.LineWidth = line_width;
			
			if (add_data.Count > 0)
				spectrum.AddData = add_data.ToArray();

			return spectrum;
		}

		public static AddData ReadAdditionalData(FileInfo file)
		{
			StreamReader stream = file.OpenText();

			AddData add_data = new AddData();
			
			// the separator regex and culture can be changed while parsing the header!
			Regex regex = new Regex(CSV.Parser.DefaultSeparator);
			CultureInfo current_culture = CSV.DEFAULT_CULTURE;
			
			string line;
			int skipped = 0;
			int line_number = 0;

			while ( (line = stream.ReadLine()) != null )
			{
				++line_number;
				string[] s = regex.Split(line);

				try
				{
					Double.Parse(s[0],
					             NumberStyles.AllowDecimalPoint|
					             NumberStyles.AllowExponent,
					             current_culture);
					
					Double.Parse(s[1],
					             NumberStyles.AllowDecimalPoint|
					             NumberStyles.AllowExponent,
					             current_culture);
					
					// csv section has started -> no more header data available
					break;
				}
				catch (Exception exx)
				{
					++skipped;

					if (line_number > Parser.MaxHeaderLines)
					{
						stream.Close();
						throw new Exception(Catalog.GetString("Cannot read csv file: Header seems to be to long") + 
						                                      " (" + exx.Message + ").");
					}
					
					try
					{
						string new_culture = (string)CSV.ParseLine(line, CSV.Parser.Culture, current_culture);
						current_culture = new CultureInfo(new_culture);
						regex = new Regex(current_culture.TextInfo.ListSeparator);
						continue;
					} 
					catch (InvalidDataException) {}
					catch (Exception ex)
					{
						stream.Close();
						throw ex;
					}

					try
					{
						add_data.DateTime = 
							(DateTime)CSV.ParseLine(line, CSV.Parser.SpectrumTime, current_culture);
						continue;
					} 
					catch (InvalidDataException) {}
					catch (Exception ex)
					{
						stream.Close();
						throw ex;
					}

					try
					{
						add_data.Serial = 
							(string)CSV.ParseLine(line, CSV.Parser.SerialNumber, current_culture);
						continue;
					} 
					catch (InvalidDataException) {}
					catch (Exception ex)
					{
						stream.Close();
						throw ex;
					}

					try
					{
						add_data.Data.Add((uint)CSV.ParseLine(line, CSV.Parser.AddData, current_culture));
						continue;
					} 
					catch (InvalidDataException) {}
					catch (Exception ex)
					{
						stream.Close();
						throw ex;
					}
				}
			}
			stream.Close();
			
			return add_data;
		}
		
		public static List<AddData> ReadAdditionalData(DirectoryInfo dir)
		{
			FileInfo[] files = dir.GetFiles("*.csv", SearchOption.AllDirectories);
			List<AddData> list = new List<AddData>();
			
			foreach (FileInfo file in files)
			{
				AddData add_data = ReadAdditionalData(file);
				list.Add(add_data);
			}
			
			return list;
		}

        public static void Write(Spectrum spectrum, string fname, CultureInfo culture, byte[] salt)
        {
            using (FileStream stream = new FileStream(fname, FileMode.Create, FileAccess.Write))
            {
                CSV.Write(spectrum, stream, culture, salt);
            }
        }

        public static void Write(Spectrum spectrum, Stream stream, CultureInfo culture, byte[] salt)
        {
            byte[] checksum = null;

            if (salt != null && salt.Length != 0)
                checksum = CSV.CreateChecksum(spectrum, salt);

            using (StreamWriter writer = new StreamWriter(stream))
            {
                CSV._Write(spectrum, writer, culture, checksum);
            }
        }

		public static void Write(Spectrum spectrum, string fname)
		{
			CSV.Write(spectrum, fname, CSV.DEFAULT_CULTURE);
		}

		public static void Write(Spectrum spectrum, string fname, CultureInfo culture)
		{
            if (!fname.ToLower().EndsWith(".csv", StringComparison.InvariantCulture))
				fname += ".csv";
			
			using (Stream stream = new FileStream(fname, FileMode.Create, FileAccess.Write))
			{
				CSV.Write(spectrum, stream, culture);
			}

			spectrum.FileInfo = new FileInfo(fname);
		}
		
		
		public static void Write(Spectrum spectrum, Stream stream, CultureInfo culture)
		{
			using (StreamWriter writer = new StreamWriter(stream))
			{
				CSV.Write(spectrum, writer, culture);
			}
		}
		
		public static void Write(Spectrum spectrum, StreamWriter writer, CultureInfo culture)
        {
            CSV._Write(spectrum, writer, culture, null);
        }

        private static void _Write(Spectrum spectrum, StreamWriter writer, CultureInfo culture, byte[] checksum)
		{
			writer.WriteLine("#");
			writer.WriteLine("# " + Parser.Culture + "=" + culture.ToString());
			writer.WriteLine("# " + Parser.SpectrumTime + "=" 
			                      + spectrum.Timestamp.ToString(Parser.DateTimeFormat));

            if (checksum != null)
                writer.WriteLine("# " + Parser.Checksum + "=" + CSV.GetStringFromHash(checksum));

			writer.WriteLine("# " + Parser.DarkIntensity + "="  
			                      + spectrum.DarkIntensity.Intensity.ToString(culture));
			writer.WriteLine("# " + Parser.DarkIntensitySigma + "=" 
			                      + spectrum.DarkIntensity.Sigma.ToString(culture));
			writer.WriteLine("# " + Parser.DarkIntensityTime + "=" 
				                  + spectrum.DarkIntensity.DateTime.ToString(Parser.DateTimeFormat));
				
			if (spectrum.HasLinearDistortion)
			{
				writer.Write("# " + Parser.LinearDistortion + "=");
				writer.Write(spectrum.LinearDistortion.Offset.ToString(culture));
				writer.Write(culture.TextInfo.ListSeparator);
				writer.Write(spectrum.LinearDistortion.Factor.ToString(culture));
				writer.WriteLine();
				
				writer.WriteLine("# " + Parser.LinearDistortionTime + "="
				                      + spectrum.LinearDistortion.DateTime.ToString(CSV.Parser.DateTimeFormat));
			}
			
			if (spectrum.HasWavelengthCorrection)
			{
				writer.WriteLine("# " + Parser.WavelengthCorrection + "=" + spectrum.WavelengthCorrection.ToString(culture));
				writer.WriteLine("# " + Parser.WavelengthCorrectionTime + "=" 
				                      + spectrum.WavelengthCorrection.DateTime.ToString(CSV.Parser.DateTimeFormat));
			}

			if (spectrum.HasWavelengthLimits)
				writer.WriteLine("# " + Parser.WavelengthLimits + "=" + spectrum.WavelengthLimits.ToString(culture));

			if (spectrum.HasAdcCorrection)
			{
				writer.Write("# " + Parser.AdcCorrection + "=");
				for (int ix=0; ix < spectrum.AdcCorrection.Count; ++ix)
				{
					writer.Write(spectrum.AdcCorrection.X[ix].ToString(culture));
					writer.Write(culture.TextInfo.ListSeparator);
					writer.Write(spectrum.AdcCorrection.Y[ix].ToString(culture));
					if (ix < spectrum.AdcCorrection.Count-1)
						writer.Write(culture.TextInfo.ListSeparator);
					else
						writer.WriteLine();
				}
			}
			
			writer.WriteLine("# " + Parser.LimitBandwidth + "=" + spectrum.LimitBandwidth.ToString(culture));
			writer.WriteLine("# " + Parser.SerialNumber + "=" + spectrum.Serial);
			writer.WriteLine("# " + Parser.FirmwareVersion + "=" + spectrum.FirmwareVersion);
			writer.WriteLine("# " + Parser.FirmwareRevision + "=" + spectrum.FirmwareRevision);
			writer.WriteLine("# " + Parser.LutTimestamp + "=" + spectrum.LutTimestamp);
			
			if (spectrum.HardwareInfo != null && spectrum.HardwareInfo.Length >= 4)
			{
				writer.Write("# " + Parser.HardwareVersionInfo + "=");
				for (int ix=0; ix < spectrum.HardwareInfo.Length; ++ix)
				{
					writer.Write(spectrum.HardwareInfo[ix].ToString(culture));
					if (ix < spectrum.HardwareInfo.Length-1)
						writer.Write(culture.TextInfo.ListSeparator);
					else
						writer.WriteLine();
				}
			}
			
			writer.WriteLine("# " + Parser.SpectralResolution + "=" + spectrum.SpectralResolution.ToString(culture));
			writer.WriteLine("# " + Parser.AverageCount + "=" + spectrum.AverageCount.ToString(culture));

			if (spectrum.HasAbsorbance)
			{
				double max_absorbance = DataSet.AbsorbanceLimit(spectrum.Background.Intensity, 
				                                              spectrum.DarkIntensity);
				writer.WriteLine("# " + Parser.MaxAbsorbance + "=" + max_absorbance.ToString(culture));
			}
			
			if (spectrum.SpectrumType != SpectrumType.Unknown)
				writer.WriteLine("# " + Parser.SpectrumType + "=" + spectrum.SpectrumType.ToString());
			
			if (spectrum.ProbeType != ProbeType.Unknown)
				writer.WriteLine("# " + Parser.ProbeType + "=" + spectrum.ProbeType.ToString());
			
			if (!string.IsNullOrEmpty(spectrum.Creator))
				writer.WriteLine("# " + Parser.Creator + "=" + spectrum.Creator);
			
			if (!string.IsNullOrEmpty(spectrum.Label) && !spectrum.DefaultLabel)
				writer.WriteLine("# " + Parser.Label + "=" + spectrum.Label);
			
			if (!spectrum.DefaultStyle)
			{
				writer.Write("# " + Parser.LineColor + "=");
				writer.WriteLine("{1}{0}{2}{0}{3}{0}{4}", culture.TextInfo.ListSeparator,
				                 spectrum.Color.A, spectrum.Color.R, 
				                 spectrum.Color.G, spectrum.Color.B);
				writer.WriteLine("# " + Parser.LineStyle + "=" + spectrum.LineStyle.ToString());
				writer.WriteLine("# " + Parser.LineWidth + "=" + spectrum.LineWidth.ToString(culture));
			}
			
			if (spectrum.Comment != string.Empty)
			{
                string[] lines = spectrum.Comment.Split('\n', '\r');
				
				foreach (string line in lines)
				{
					if (string.IsNullOrEmpty(line.Trim()))
					    continue;
					writer.WriteLine("# " + Parser.Comment + "=" + line);
				}
			}
				
			if (spectrum.AddData != null && spectrum.AddData.Length > 0)
			{
				foreach (uint data in spectrum.AddData)
				{
					writer.WriteLine("# " + Parser.AddData + "=" + data.ToString("d"));
				}
			}
			
			writer.WriteLine("#");
			writer.WriteLine("# Raw wavelength" + culture.TextInfo.ListSeparator +
			                 "Raw intensity" + culture.TextInfo.ListSeparator +
			                 "Raw absorbance");
			
			if (spectrum.HasAbsorbance)
			{
				bool sav_limit_bandwith = spectrum.LimitBandwidth;
				spectrum.LimitBandwidth = false;
				
				LinearDistortion sav_ld = spectrum.LinearDistortion;
				spectrum.LinearDistortion = null;
				
				DataSet sav_adc_correction = spectrum.AdcCorrection;
				spectrum.AdcCorrection = null;

				WavelengthLimits sav_limits = spectrum.WavelengthLimits;
				spectrum.WavelengthLimits = null;
				
				try
				{
					for (int ix=0; ix < spectrum.Count; ++ix)
					{
						writer.WriteLine(spectrum.RawIntensity.X[ix].ToString(culture)
						                 + culture.TextInfo.ListSeparator +
						                 spectrum.RawIntensity.Y[ix].ToString(culture)
						                 + culture.TextInfo.ListSeparator +
						                 spectrum.Absorbance.Y[ix].ToString(culture)
						                 );
					}
				}
				catch (Exception ex)
				{
					throw ex;
				}
				finally
				{
					spectrum.LimitBandwidth   = sav_limit_bandwith;
					spectrum.LinearDistortion = sav_ld;
					spectrum.AdcCorrection    = sav_adc_correction;
					spectrum.WavelengthLimits = sav_limits;
				}
			}
			else
			{
				for (int ix=0; ix < spectrum.Count; ++ix)
				{
					writer.WriteLine(spectrum.RawIntensity.X[ix].ToString(culture)
					                 + culture.TextInfo.ListSeparator +
					                 spectrum.RawIntensity.Y[ix].ToString(culture)
					                 );
				}
			}
		}

        public static bool CheckIntegrity(string fname, byte[] salt)
        {
            using (FileStream reader = new FileStream(fname, FileMode.Open, FileAccess.Read))
            {
                return CSV.CheckIntegrity(reader, salt);
            }
        }

        public static bool CheckIntegrity(Stream stream, byte[] salt)
        {
            Regex regex = new Regex(CSV.Parser.DefaultSeparator);

            byte[] saved_checksum = null;

            using (MemoryStream ms = new MemoryStream())
            {
                stream.CopyTo(ms);
                stream.Position = 0;

                using (StreamReader reader = new StreamReader(stream))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)            
                    {

                        if (line.StartsWith("#") == false)
                            break;

                        if (line.StartsWith("# " + Parser.Checksum) == false)
                            continue;

                        string[] s = line.Split('=');

                        if (s.Length != 2)
                            throw new FormatException(Catalog.GetString("Cannot parse header line: Invalid checksum data."));

                        saved_checksum = CSV.GetHashFromString(s[1]);
                        break;
                    }
                }

                if (saved_checksum == null)
                    throw new InvalidDataException(Catalog.GetString("Spectrum file has no checksum."));

                byte[] actual_checksum = CSV.CreateChecksum(ms, salt);
                return actual_checksum.SequenceEqual(saved_checksum);
            }
        }
		
		public static bool _IgnoreCorrection
		{
			get { return CSV.ignore_correction;  }
			set { CSV.ignore_correction = value; }
		}
	}
}
