// CurrentSpectra.cs created with MonoDevelop
// User: klose at 15:55 02.07.2010
// CVS release: $Id: CurrentSpectra.cs,v 1.4 2011-04-19 12:36:57 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.Collections.Generic;
using System.Drawing;
using Gtk;

using Hiperscan.SGS;
using Hiperscan.Spectroscopy;
using Hiperscan.GUI.Figure;
using Hiperscan.Extensions;
using Hiperscan.Unix;

	
namespace Hiperscan.GUI
{
//	public class CurrentSpectraList
//	{
//		private List<CurrentSpectra> list;
//		private CurrentSpectra current;
//		
//		public delegate void CurrentSpectraListChangedHandler(CurrentSpectraList list, ICurrentSpectra current_spectra, bool ds_changed);
//		public event         CurrentSpectraListChangedHandler Changed;
//		
//		public event CurrentSpectra.LastEntryReachedHandler  LastEntryReached;
//		public event CurrentSpectra.FirstEntryReachedHandler FirstEntryReached;
//		public event CurrentSpectra.UndoPossibleHandler UndoPossible;
//		public event CurrentSpectra.RedoPossibleHandler RedoPossible;
//
//		public CurrentSpectraList() : base()
//		{
//			this.list = new List<CurrentSpectra>();
//		}
//		
//		public void Add(CurrentSpectra item)
//		{
//			this.ConnectEvents(item);
//			this.list.Add(item);
//		}
//		
//		public void Remove(CurrentSpectra item)
//		{
//			this.DisconnectEvents(item);
//			this.list.Remove(item);
//			if (this.Changed != null)
//				this.Changed(this, this.Current, false);
//		}
//		
//		public void RemoveAt(int index)
//		{
//			this.DisconnectEvents(this.list[index]);
//			this.list.RemoveAt(index);
//		}
//		
//		public void Clear()
//		{
//			foreach (CurrentSpectra item in this.list)
//			{
//				this.DisconnectEvents(item);
//			}
//			this.list.Clear();
//		}
//		
//		private void ConnectEvents(CurrentSpectra item)
//		{
//			item.Changed           += this.OnCurrentSpectraChanged;
//			item.LastEntryReached  += this.OnLastEntryReached;
//			item.FirstEntryReached += this.OnFirstEntryReached;
//			item.UndoPossible      += this.OnUndoPosible;
//			item.RedoPossible      += this.RedoPossible;
//		}
//		
//		private void DisconnectEvents(CurrentSpectra item)
//		{
//			item.Changed           -= this.OnCurrentSpectraChanged;
//			item.LastEntryReached  -= this.OnLastEntryReached;
//			item.FirstEntryReached -= this.OnFirstEntryReached;
//			item.UndoPossible      -= this.OnUndoPosible;
//			item.RedoPossible      -= this.RedoPossible;
//		}
//
//		private void OnCurrentSpectraChanged(ICurrentSpectra current_spectra, bool ds_changed)
//		{
//			if (this.Changed != null)
//				this.Changed(this, current_spectra, ds_changed);
//		}
//		
//		private void OnLastEntryReached()
//		{
//			if (this.LastEntryReached != null)
//				this.LastEntryReached();
//		}
//		
//		private void OnFirstEntryReached()
//		{
//			if (this.FirstEntryReached != null)
//				this.FirstEntryReached();
//		}
//		
//		private void OnUndoPosible()
//		{
//			if (this.UndoPossible != null)
//				this.UndoPossible();
//		}
//		
//		private void OnRedoPosible()
//		{
//			if (this.RedoPossible != null)
//				this.RedoPossible();
//		}
//		
//		public CurrentSpectra this[int ix]
//		{
//			get { return this.list[ix];  }
//			set { this.list[ix] = value; }
//		}
//		
//		public CurrentSpectra Current
//		{
//			get { return this.current;  }
//			set { this.current = value; }
//		}
//	}
	
	public class CurrentSpectra : Hiperscan.Extensions.ICurrentSpectra
	{
		private List<Dictionary<string,Spectrum>> spectra_history;
		private PlotInfo plot_info;
		
		private int current_entry;
		
		private const int max_history_count = 30;
		
		public event Hiperscan.Extensions.CurrentSpectraChangedHandler Changed;
		
		public delegate void LastEntryReachedHandler(CurrentSpectra current_spectra);
		public event         LastEntryReachedHandler LastEntryReached;
		
		public delegate void FirstEntryReachedHandler(CurrentSpectra current_spectra);
		public event         FirstEntryReachedHandler FirstEntryReached;
		
		public delegate void UndoPossibleHandler(CurrentSpectra current_spectra);
		public event         UndoPossibleHandler UndoPossible;
		
		public delegate void RedoPossibleHandler(CurrentSpectra current_spectra);
		public event         RedoPossibleHandler RedoPossible;
		
		
		public CurrentSpectra(PlotInfo plot_info)
		{
			this.plot_info = plot_info;
			this.spectra_history = new List<Dictionary<string,Spectrum>>();
			this.spectra_history.Add(new Dictionary<string,Spectrum>());
			this.current_entry = 0;
		}
		
		public CurrentSpectra(CurrentSpectra current)
		{
			this.plot_info = current.PlotInfo;
			
			lock (current)
			{
				this.spectra_history = new List<Dictionary<string,Spectrum>>();
				
				foreach (Dictionary<string,Spectrum> spectra in current.HistoryEntries)
					this.spectra_history.Add(new Dictionary<string,Spectrum>(spectra));
				
				this.current_entry = current.CurrentHistoryEntry;
			}
		}
		
		public void NotifyChanges()
		{
			lock (this)
			{
				if (this.spectra_history.Count == 1)
				{
					if (this.FirstEntryReached != null)
						this.FirstEntryReached(this);
					if (this.LastEntryReached  != null)
						this.LastEntryReached(this);
					if (this.Changed != null)
						this.Changed(this, false);
					return;
				}
				
				if (this.current_entry == this.spectra_history.Count-1 &&
				    this.LastEntryReached != null)
					this.LastEntryReached(this);
				else if (this.RedoPossible != null)
					this.RedoPossible(this);
				
				if (this.current_entry ==  0 &&
				    this.FirstEntryReached != null)
					this.FirstEntryReached(this);
				else if (this.UndoPossible != null)
					this.UndoPossible(this);

				if (this.Changed != null)
					this.Changed(this, false);
			}
		}
		
		public void Add(string id, Spectrum spectrum, bool notify)
		{
			lock (this)
			{
				this.SetAttributes(spectrum);
				this.spectra_history[this.current_entry].Add(id, spectrum);
				
				if (notify)
					this.NotifyChanges();
			}
		}
		
		public bool Contains(string id)
		{
			lock (this)
				return this.spectra_history[this.current_entry].ContainsKey(id);
		}
		
		public void Remove(string id, bool notify)
		{
			lock (this)
			{
				this.spectra_history[this.current_entry].Remove(id);

				if (notify)
					this.NotifyChanges();
			}
		}
		
		public void Clear()
		{
			lock (this)
			{
				this.spectra_history[this.current_entry].Clear();
				this.NotifyChanges();
			}
		}
		
		public Spectrum GetByLabel(string label)
		{
			lock (this)
			{
				foreach (Spectrum spectrum in this.spectra_history[this.current_entry].Values)
				{
					if (spectrum.Label == label)
						return spectrum;
				}
				return null;
			}
		}
		
		public int Count
		{
			get
			{ 
				lock (this)
					return this.spectra_history[this.current_entry].Count;
			}
		}
		
		public int CurrentHistoryEntry
		{
			get
			{
				lock (this)
					return this.current_entry;
			}
		}
		
		public Dictionary<string,Spectrum>.ValueCollection Values
		{
			get
			{
				lock (this)
					return this.spectra_history[this.current_entry].Values;
			}
		}
		
		public List<Dictionary<string,Spectrum>> HistoryEntries
		{
			get
			{
				lock (this)
					return this.spectra_history;
			}
		}
		
		public Dictionary<string,Spectrum>.KeyCollection Keys
		{
			get
			{
				lock (this)
					return this.spectra_history[this.current_entry].Keys;
			}
		}

		public List<string> ZOrderKeys
		{
			get
			{
				List<KeyValuePair<string,int>> z_order = new List<KeyValuePair<string,int>>();

				lock (this)
				{
					foreach (Spectrum spectrum in this.Values)
					{
						z_order.Add(new KeyValuePair<string,int>(spectrum.Id, spectrum.ZOrder));
					}
					z_order.Sort(delegate(KeyValuePair<string,int> lhs, KeyValuePair<string,int> rhs) {
						return lhs.Value.CompareTo(rhs.Value);
					});

					List<string> keys = new List<string>();
					foreach (KeyValuePair<string,int> kv in z_order)
					{
						keys.Add(kv.Key);
					}

					return keys;
				}
			}
		}
		
		public bool ContainsLabel(string label)
		{
			lock (this)
			{
				bool found = false;
				
				foreach (Spectrum spectrum in this.spectra_history[this.current_entry].Values)
				{
					if (spectrum.Label == label)
					{
						found = true;
						break;
					}
				}
				return found;
			}
		}
		
		private void SetAttributes(Spectrum spectrum)
		{
//				if (spectrum.SpectrumType == SpectrumType.Stream ||
//				    spectrum.SpectrumType == SpectrumType.QuickStream)
//				{
//					spectrum.Color = UserInterface.Config.StreamColor;
//				}
//				else 
			if (spectrum.SpectrumType == SpectrumType.Preview)
			{
				spectrum.Color = Color.Aqua;
			}
			else
			{
				ColorPicker.Clear();
				lock (this)
				{
					foreach (Spectrum s in this.Values)
					{
						if (s.Color != Color.Empty)
							ColorPicker.Existing(s.Color);
						
						if (s.Id == spectrum.Id)
						{
							bool sav_default = spectrum.DefaultStyle;
							spectrum.Color = s.Color;
							spectrum.LineStyle = s.LineStyle;
							spectrum.LineWidth = s.LineWidth;
							spectrum.DefaultStyle = sav_default;
							return;
						}
					}
				}
				if (spectrum.Color == Color.Empty)
				{
					bool sav_default = spectrum.DefaultStyle;
					spectrum.Color = ColorPicker.New();
					spectrum.DefaultStyle = sav_default;
				}
			}
		}                
		
		public Spectrum GetById(string id)
		{
			return this[id];
		}
		
		public Spectrum this[string id]
		{
			get
			{
				lock (this)
					return this.spectra_history[this.current_entry][id];
			}
			set
			{ 
				lock (this)
				{
					this.SetAttributes(value);
					value.ZOrder = this.spectra_history[this.current_entry][id].ZOrder;
					this.spectra_history[this.current_entry][id] = value;
//					this.NotifyChanges();
				}
			}
		}
		
		public void AddHistoryEntry()
		{
			lock (this)
			{
				if (this.current_entry < this.spectra_history.Count-1)
				{
					int count = this.spectra_history.Count - this.current_entry - 1;
					this.spectra_history.RemoveRange(this.current_entry+1, count);
				}
				
				if (this.spectra_history.Count == max_history_count)
				{
					this.spectra_history.RemoveAt(0);
					--this.current_entry;
				}
			
//					Dictionary<string,Spectrum> current = new Dictionary<string,Spectrum>();
//					foreach (string key in this.spectra_history[this.current_entry].Keys)
//					{
//						Spectrum spectrum = this.spectra_history[this.current_entry][key];
//						if (!spectrum.IsPreview && spectrum.SpectrumType == SpectrumType.Single)
//							current.Add(key, spectrum);
//					}
				this.spectra_history.Add(new Dictionary<string,Spectrum>(this.spectra_history[this.current_entry]));
				
				Dictionary<string,Spectrum> prev_entry = this.spectra_history[this.spectra_history.Count-2];
				if (prev_entry.ContainsKey("9_preview"))
					prev_entry.Remove("9_preview");
				
				++this.current_entry;
			}
		}
		
		public void Undo()
		{
			lock (this)
			{
				if (this.current_entry > 0)
				{
					if (this.spectra_history[this.current_entry].ContainsKey("9_preview"))
						this.spectra_history[this.current_entry].Remove("9_preview");
					--this.current_entry;
				}
				
				this.NotifyChanges();
			}
		}
		
		public void Redo()
		{
			lock (this)
			{
				if (this.current_entry < this.spectra_history.Count-1)
					++this.current_entry;
				
				this.NotifyChanges();
			}
		}

		public override int GetHashCode ()
		{
			int hash = 0;

			foreach (Spectrum spectrum in this.Values)
			{
				hash ^= spectrum.GetHashCode();
			}

			return hash;
		}
		
		public bool UndoIsPossible
		{
			get { return this.current_entry != 0; }
		}
		
		public bool RedoIsPossible
		{
			get { return this.current_entry != this.spectra_history.Count-1; }
		}
		
		public PlotInfo PlotInfo
		{
			get { return this.plot_info; }
		}
	}
}