// DirectoryProperty.cs created with MonoDevelop
// User: klose at 13:41 16.02.2009
// CVS release: $Id: DirectoryProperty.cs,v 1.15 2010-08-11 14:10:52 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2009  Thomas Klose, 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.Globalization;

using Hiperscan.SGS;
using Hiperscan.Spectroscopy;
using Hiperscan.FileIO;
using Hiperscan.Unix;


namespace Hiperscan.GUI
{
	public enum SpectrumFileType
	{
		CSV
	}
	
	public enum OutputCulture
	{
		English,
		German,
		System
	}
	
	public class AutoSaveConfig
	{
		private DirectoryProperty single_dir;
		private DirectoryProperty stream_dir;

		public AutoSaveConfig(DirectoryProperty single_dir, DirectoryProperty stream_dir)
		{
			this.single_dir = single_dir;
			this.stream_dir = stream_dir;
			
			this.single_dir.AutoSaveStream = false;
			this.stream_dir.AutoSaveSingle = false;
		}
		
		public void DisconnectSingleDevice()
		{
			if (this.single_dir != null)
				this.single_dir.DisconnectSingleDevice();
		}
		
		public void DisconnectStreamDevice()
		{
			if (this.stream_dir != null)
				this.stream_dir.DisconnectStreamDevice();
		}
		
		public DirectoryProperty SingleDir
		{
			get { return this.single_dir; }
			set
			{
				if (this.single_dir != null)
					this.single_dir.DisconnectSingleDevice();
				this.single_dir = value;
				this.single_dir.AutoSaveStream = false;
			}
		}

		public DirectoryProperty StreamDir
		{
			get { return this.stream_dir; }
			set
			{
				if (this.stream_dir != null)
					this.stream_dir.DisconnectStreamDevice();
				this.stream_dir = value;
				this.stream_dir.AutoSaveSingle = false;
			}
		}
	}
	
	public class DirectoryProperty : System.IComparable<DirectoryProperty>
	{
		private DirectoryInfo info;
		
		private Device associated_device = null;
		
		private bool active = true;
		private bool auto_save_single = false;
		private bool auto_save_stream = false;

		private CultureInfo culture_info;
		private OutputCulture output_culture;
		
		private string single_filemask;
		private string stream_filemask;
		private string single_suffix;
		private string stream_suffix;

		private SpectrumFileType single_filetype;
		private SpectrumFileType stream_filetype;
		
		private string spectrum_comment;
		
		
		private DirectoryProperty()
		{
			this.auto_save_single = false;
			this.auto_save_stream = false;
			this.OutputCulture    = UserInterface.Settings.Current.StandardOutputCulture;
			this.single_filemask  = UserInterface.Settings.Current.SingleFileMask;
			this.stream_filemask  = UserInterface.Settings.Current.StreamFileMask;
			this.SingleFiletype   = SpectrumFileType.CSV;
			this.StreamFiletype   = SpectrumFileType.CSV;
			this.spectrum_comment = string.Empty;
		}
		
		public DirectoryProperty(DirectoryInfo info) : this()
		{
			this.info = info;
		}
		
		public DirectoryProperty(string path) : this()
		{
			this.info = new DirectoryInfo(path);
		}
		
		public DirectoryProperty(DirectoryProperty dir) : this()
		{
			this.info = dir.info;
			
			this.auto_save_single = dir.AutoSaveSingle;
			this.auto_save_stream = dir.AutoSaveStream;
			
			this.associated_device = dir.AssociatedDevice;
		}

		public int CompareTo(DirectoryProperty dp)
		{
			if (dp == null)
				return 1;
			
			return this.Info.Name.CompareTo(dp.Info.Name);
		}
		
		private string AssembleFilename(Spectrum spectrum, string filemask, string suffix)
		{
			return DirectoryProperty.AssembleFilename(this.Info.FullName, spectrum, filemask, suffix);
		}

		public static string AssembleFilename(string path, Spectrum spectrum, string filemask, string suffix)
		{
			path += System.IO.Path.DirectorySeparatorChar;
			
			// compatibility with deprecated format
			filemask = filemask.Replace("yyyy-MM-dd_HH-mm-ss", "%time%");
			
			if (string.IsNullOrEmpty(spectrum.Serial))
				filemask = filemask.Replace("%serial%",  "*");
			else
				filemask = filemask.Replace("%serial%",  spectrum.Serial);
			
			if (spectrum.Number < 0)
				filemask = filemask.Replace("%number%",  "*");
			else
				filemask = filemask.Replace("%number%",  spectrum.Number.ToString("d4"));
			
			if (spectrum.AverageCount < 0)
				filemask = filemask.Replace("%average%", "*");
			else
				filemask = filemask.Replace("%average%", spectrum.AverageCount.ToString());
				
			filemask = filemask.Replace("'", string.Empty);
			filemask = filemask.Insert(0, "'");
			filemask += "'";
			
			if (filemask.Contains("%time%"))
			{
				filemask = filemask.Replace("%time%", "'yyyy-MM-dd_HH-mm-ss'");
			}
			
			if (filemask.Contains("%"))
				throw new ArgumentException(Catalog.GetString("Invalid % expression."));
			
			return path + spectrum.Timestamp.ToString(filemask) + suffix;
		}
		
		public void DisconnectSingleDevice()
		{
			Console.WriteLine("Disconnect device " + this.associated_device + " from single dir " + this.Info.Name);
			try
			{
				this.associated_device.NewSingle -= this.OnNewSingle;
			}
			catch {}
		}

		public void DisconnectStreamDevice()
		{
			Console.WriteLine("Disconnect device " + this.associated_device + " from stream dir " + this.Info.Name);

			try
			{
				this.associated_device.NewStream -= this.OnNewStream;
			}
			catch {}
		}
		
		public void DisconnectDevice()
		{
			this.DisconnectSingleDevice();
			this.DisconnectStreamDevice();
		}
		
		private void OnNewSingle(Device device, Spectrum spectrum)
		{
			if (!this.AutoSaveSingle || !this.Active)
				return;

			device.SetAbsorbance(spectrum);
			device.SetWavelengthCorrection(spectrum);

			string fname = this.AssembleFilename(spectrum, this.single_filemask, this.single_suffix);
			
			if (!string.IsNullOrEmpty(this.SpectrumComment))
				spectrum.Comment = this.SpectrumComment;
			
			UserInterface._SetCreator(spectrum);

			try
			{
				CSV.Write(spectrum, fname, this.culture_info);
			}
			catch (Exception ex)
			{
				this.Active = false;
				string msg = string.Format(Catalog.GetString("Cannot automatically save single spectrum in directory '{0}': {1}" + 
				                                             "\n\n Disabling the auto save function."), 
				                           this.info.FullName, ex.Message);
				Console.WriteLine(msg);
				Console.WriteLine(ex.ToString());
				UserInterface.Queues.MessageQueue.Enqueue(msg);
			}
		}
		
		private void OnNewStream(Device device, Spectrum spectrum)
		{
			if (!this.AutoSaveStream || !this.Active)
				return;
			
			device.SetAbsorbance(spectrum);
			device.SetWavelengthCorrection(spectrum);
			
			string fname = this.AssembleFilename(spectrum, this.stream_filemask, this.stream_suffix);
			
			if (!string.IsNullOrEmpty(this.SpectrumComment))
				spectrum.Comment = this.SpectrumComment;

			UserInterface._SetCreator(spectrum);

			try
			{
				spectrum.Label = string.Empty;
				CSV.Write(spectrum, fname, this.culture_info);
			}
			catch (Exception ex)
			{
				this.Active = false;
				string msg = string.Format(Catalog.GetString("Cannot automatically save stream spectrum in directory '{0}': {1}" +
				                                             "\n\n Disabling the auto save function."),
				                           this.info.FullName, ex.Message);
				Console.WriteLine(msg);
				Console.WriteLine(ex.ToString());
				UserInterface.Queues.MessageQueue.Enqueue(msg);
			}
		}
		
		public DirectoryInfo Info
		{
			get { return this.info; }
		}
		
		public Device AssociatedDevice
		{
			get { return this.associated_device;  }
			set
			{ 
				if (value == this.associated_device)
					return;
				
				this.DisconnectDevice();
				this.associated_device = value;

				if (this.associated_device != null)
				{
					Console.WriteLine("Connect device " + this.associated_device + " with dir " + this.Info.Name);
					this.associated_device.NewSingle += this.OnNewSingle;
					this.associated_device.NewStream += this.OnNewStream;
				}
			}
		}
		
		public bool Active
		{
			get { return this.active;  }
			set { this.active = value; }
		}
		
		public bool AutoSaveSingle
		{
			get { return this.auto_save_single;  }
			set { this.auto_save_single = value; }
		}
		
		public bool AutoSaveStream
		{
			get { return this.auto_save_stream;  }
			set { this.auto_save_stream = value; }
		}
		
		public OutputCulture OutputCulture
		{
			get { return this.output_culture;  }
			set
			{
				switch (value)
				{
					
				case OutputCulture.English:
					this.culture_info = new CultureInfo("en-US");
					break;
				
				case OutputCulture.German:
					this.culture_info = new CultureInfo("de-DE");
					break;
					
				case OutputCulture.System:
					this.culture_info = CultureInfo.CurrentCulture;
					break;

				default:
					this.culture_info = new CultureInfo("en-US");
					break;
				}

				this.output_culture = value;
			}
		}
		
		public string SingleFilemask
		{
			get { return this.single_filemask;  }
			set { this.single_filemask = value; }
		}

		public string StreamFilemask
		{
			get { return this.stream_filemask;  }
			set { this.stream_filemask = value; }
		}
		
		public SpectrumFileType SingleFiletype
		{
			get { return this.single_filetype;  }
			set
			{
				switch (value)
				{ 
				case SpectrumFileType.CSV:
					this.single_suffix = ".csv";
					break;
					
				default:
					this.single_suffix = ".csv";
					break;
				}
				
				this.single_filetype = value;
			}
		}

		public SpectrumFileType StreamFiletype
		{
			get { return this.stream_filetype;  }
			set
			{
				switch (value)
				{
				case SpectrumFileType.CSV:
					this.stream_suffix = ".csv";
					break;
					
				default:
					this.stream_suffix = ".csv";
					break;
				}
				
				this.stream_filetype = value;
			}
		}
		
		public string SpectrumComment
		{
			get { return this.spectrum_comment;  }
			set { this.spectrum_comment = value; }
		}
		
		public bool HasComment
		{
			get { return !string.IsNullOrEmpty(this.SpectrumComment); }
		}
	}
}
