//
//  SampleIdWindow.cs
//
// QuickStep: Acquire, view and identify spectra 
// Copyright (C) 2010-2017  Thomas Klose & Torsten Schache, 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.Text.RegularExpressions;
using System.Collections.Generic;
using Glade;
using Gtk;
using Mono.Unix;

using Hiperscan.Common;
using Hiperscan.Spectroscopy;
using Hiperscan.FileIO;


namespace Hiperscan.Extensions.Acquisition
{

	public class SampleIdWindow
	{
		[Widget] Gtk.Window sample_id_window = null;
		[Widget] Gtk.Entry  sample_id_entry = null;
		[Widget] Gtk.Entry  series_id_entry = null;

		[Widget] Gtk.Label file_name_label = null;

		[Widget] Gtk.Button ok_button1 = null;

		private static string series_id_cache = string.Empty;
        private static string serial_cache = string.Empty;

		private static Dictionary<string,string> saved_spectra = new Dictionary<string,string>();
		private static string id_postfix = Environment.GetEnvironmentVariable(Env.Plugin.ACQUISITION_ID_POSTFIX);

		public SampleIdWindow()
		{
			Glade.XML gui = new Glade.XML(null, "Acquisition.Acquisition.glade", "sample_id_window", "Hiperscan");
			gui.Autoconnect(this);

			this.sample_id_entry.Changed += this.UpdateOkButton;
			this.series_id_entry.Changed += this.UpdateOkButton;

			this.series_id_entry.Text = SampleIdWindow.series_id_cache;

			this.sample_id_window.TransientFor = Plugin.host.MainWindow;
			this.sample_id_window.ShowAll();
		}

		internal void OnOkButtonClicked(object sender, EventArgs args)
		{
			try
			{
				bool skipped = false;
				bool saved   = false;

				int ix = 0;
				int ix_si = 0;
				SpectrumType last_spectrum_type = SpectrumType.Unknown;

				bool auto_increase_number = false;
				bool si_spectra = false;

				foreach (Spectrum spectrum in Plugin.host.CurrentSpectra.Values)
				{
					if (spectrum.IsFromFile)
						continue;

					if (spectrum.SpectrumType != SpectrumType.SolidSpecimen &&
					    spectrum.SpectrumType != SpectrumType.FluidSpecimen)
					{
						skipped = true;
						continue;
					}

					if (last_spectrum_type != SpectrumType.Unknown &&
					    spectrum.SpectrumType != last_spectrum_type)
						throw new Exception(Catalog.GetString("Cannot mix solid and fluid spectra."));

					string path = Path.Combine(Handlers.GetSavePath(), "Rohdaten");
					string si_path, fname;
					if (spectrum.ProbeType == ProbeType.FinderInsert || spectrum.ProbeType == ProbeType.FinderSDInsert)
					{
						si_spectra = true;
						if (Handlers.GetSavePath() == ".QuickStep")
							si_path = Path.Combine(Handlers.GetSavePath(), "Rohdaten_SI");
						else
							si_path = Path.Combine(Handlers.GetSavePath() + "_SI", "Rohdaten_SI");
						fname = this.sample_id_entry.Text + "SI" + "_" + this.series_id_entry.Text + "_" + (++ix_si).ToString() + ".csv";
					}
					else if (!string.IsNullOrEmpty(id_postfix))
					{
						si_path = null;
						fname = this.sample_id_entry.Text + "_" + this.series_id_entry.Text + id_postfix + "_" + (++ix_si).ToString() + ".csv";
					}
					else
					{
						si_path = null;
						fname = this.sample_id_entry.Text + "_" + this.series_id_entry.Text + "_" + (++ix).ToString() + ".csv";
					}

					string save_path;
					if (string.IsNullOrEmpty(si_path))
					{
						if (Directory.Exists(path) == false)
							Directory.CreateDirectory(path);
						save_path = Path.Combine(path, fname);
					}
					else
					{
						if (Directory.Exists(si_path) == false)
							Directory.CreateDirectory(si_path);
						save_path = Path.Combine(si_path, fname);
					}

					 

					if (SampleIdWindow.saved_spectra.ContainsKey(spectrum.Id))
					{
						string msg = string.Format(Catalog.GetString("Spectrum '{0}' has already been saved under the filename '{1}'."),
						                           spectrum.Label, SampleIdWindow.saved_spectra[spectrum.Id]);
						throw new Exception(msg);
					}

					if (File.Exists(save_path))
					{
						if (auto_increase_number == false)
						{
							MessageDialog dialog = new MessageDialog(this.sample_id_window, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo,
							                                         Catalog.GetString("A spectrum with name '{0}' already exists. Do you want to save with " +
						                                                               "increased spectrum number anyway?"), fname);

							ResponseType response = (ResponseType)dialog.Run();
							dialog.Destroy();

							auto_increase_number = response == ResponseType.Yes;
						}

						if (auto_increase_number)
						{
							while (File.Exists(save_path))
							{
								int spectrum_ix = int.Parse(Regex.Match(save_path, @"[0-9]*\.csv$").ToString().Replace(".csv", string.Empty));
								save_path = save_path.Replace(spectrum_ix + ".csv", ++spectrum_ix + ".csv");
							}
						}
						else
						{
							throw new Exception(Catalog.GetString("The operation has been aborted by user."));
						}
					}

					CSV.Write(spectrum, save_path);
					SampleIdWindow.saved_spectra.Add(spectrum.Id, fname);

					saved = true;
					SampleIdWindow.series_id_cache = this.series_id_entry.Text;
				}

				if (skipped)
					Plugin.host.ShowInfoMessage(this.sample_id_window,
					                            Catalog.GetString("Not all shown spectra have been saved."));

				if (!saved)
					Plugin.host.ShowInfoMessage(this.sample_id_window,
					                            Catalog.GetString("No spectra have been saved."));

				if (!skipped && saved)
					Plugin.host.ClearPlot();

				if (si_spectra && saved)
				{
					string src_dir  = Path.Combine(Handlers.GetSavePath(), Catalog.GetString("Referencing"));
					string dest_dir = Path.Combine(Handlers.GetSavePath() + "_SI", Catalog.GetString("Referencing"));
					SampleIdWindow.CopyDirectory(src_dir, dest_dir);
				}
					
			}
			catch (Exception ex)
			{
				Plugin.host.ShowInfoMessage(this.sample_id_window,
				                            Catalog.GetString("Cannot save sample spectra: {0}"),
					                        ex.Message);
				Console.WriteLine("Cannot save sample spectra: " + ex.ToString());
			}
			finally
			{
				this.sample_id_window.Destroy();
			}
		}

		internal void OnCancelButtonClicked(object sender, EventArgs args)
		{
			this.sample_id_window.Destroy();
		}

		private void UpdateOkButton(object sender, EventArgs args)
		{
			if (!string.IsNullOrEmpty(Handlers.GetSavePath())  &&
				Regex.IsMatch(this.sample_id_entry.Text, @"^[0-9]{5}$") &&
			    Regex.IsMatch(this.series_id_entry.Text, @"^[A-Z]{2}$"))
			{
				this.file_name_label.Text = this.sample_id_entry.Text + "(SI)_" + this.series_id_entry.Text + "_1.csv";
				this.ok_button1.Sensitive = true;
			}
			else
			{
				this.file_name_label.Text = Catalog.GetString("invalid");
				this.ok_button1.Sensitive = false;
			}
		}

		private static void CopyDirectory(string src_dir, string dest_dir)
		{
			DirectoryInfo dir = new DirectoryInfo(src_dir);

			if (dir.Exists == false)
				throw new DirectoryNotFoundException(string.Format(Catalog.GetString("Source directory does not exist or could not be found: {0}"), src_dir));

			DirectoryInfo[] dirs = dir.GetDirectories();

			if (Directory.Exists(dest_dir) == false)
				Directory.CreateDirectory(dest_dir);

			FileInfo[] files = dir.GetFiles();
			foreach (FileInfo file in files)
			{
				string temp_path = Path.Combine(dest_dir, file.Name);
				if (File.Exists(temp_path) == false)
					file.CopyTo(temp_path, false);
			}

			foreach (DirectoryInfo subdir in dirs)
			{
				string temp_path = Path.Combine(dest_dir, subdir.Name);
				CopyDirectory(subdir.FullName, temp_path);
			}
		}

        public static string SerialNumber
        {
            set
            {
                if (value == SampleIdWindow.serial_cache)
                    return;
                SampleIdWindow.series_id_cache = string.Empty;
                SampleIdWindow.serial_cache    = value;
            }
        }
	}
}