// Message.cs created with MonoDevelop
// User: klose at 21:14 08.01.2009
// CVS release: $Id: Messages.cs,v 1.19 2011-04-19 12:36:58 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 Gtk;
using Glade;

using Hiperscan.Unix;


namespace Hiperscan.GUI
{
	public class QSMessageDialog : Gtk.MessageDialog
	{
		public QSMessageDialog(Window parent, DialogFlags flags, MessageType type, ButtonsType bt, string format, params object[] args)
			: base(parent, flags, type, bt, format, args)
		{
			if (parent != null && parent.IconList != null && parent.IconList.Length != 0)
				this.IconList = parent.IconList;
			else
				this.IconList = MainClass.QuickStepIcons;
			
			this.KeepAbove = true;

		}
		
		public new int Run()
		{
			if (MainClass.TouchScreen)
			{
				foreach (Widget w in this.ActionArea.Children)
				{
					if (w is Button)
						w.HeightRequest = MainClass.TouchScreenButtonSize;
				}
			}
			
			return base.Run();
		}
	}
	
	public class InfoMessage : QSMessageDialog
	{

		public delegate void CloseClickedHandler();

		public InfoMessage(Window parent, string format, params object[] args)
			: this (parent, false, format, args)
		{
		}

		public InfoMessage(Window parent, bool use_markup, string format, params object[] args)
			: base(parent, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, format, args)
		{
			this.Title     = MainClass.ApplicationName + " " + Catalog.GetString("Information");
			this.UseMarkup = use_markup;
			this.Present();
			this.Run();
			this.Destroy();
		}

		public InfoMessage(Window parent, string add_button, EventHandler add_button_clicked, string format, params object[] args)
			: this(parent, add_button, add_button_clicked, false, format, args)
		{
		}

		public InfoMessage(Window parent, string add_button, EventHandler add_button_clicked, bool use_markup, string format, params object[] args)
			: base(parent, DialogFlags.Modal, MessageType.Info, ButtonsType.None, format, args)
		{
			this.Title     = MainClass.ApplicationName + " " + Catalog.GetString("Information");
			this.UseMarkup = use_markup;
			Button b = new Button(add_button);
			b.Clicked += (object sender, EventArgs e) => { this.Destroy(); add_button_clicked.Invoke(sender, e); };
			b.ShowAll();
			b.CanFocus = false;
			this.ActionArea.PackStart(b);
			this.AddButton(Stock.Ok, ResponseType.Ok);
			this.Run();
			this.Destroy();
		}

		public InfoMessage(Window parent, ref bool dont_show_again, string format, params object[] args) 
			: this(parent, ref dont_show_again, false, format, args)
		{
		}

		public InfoMessage(Window parent, ref bool dont_show_again, bool use_markup, string format, params object[] args)
			: base(parent, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, format, args)
		{
			if (dont_show_again)
			{
				this.Destroy();
				return;
			}
			
			this.Title     = MainClass.ApplicationName + " " + Catalog.GetString("Information");
			this.UseMarkup = use_markup;
			
			CheckButton cb = new CheckButton(Catalog.GetString("Don't show this dialog again"));
			cb.CanFocus = false;
			this.VBox.PackStart(cb);
			cb.Show();
			
			this.Run();
			dont_show_again = cb.Active;
			this.Destroy();
		}
		
		public InfoMessage(Window parent, EventHandler h, bool use_markup, string format, params object[] args)
			: base(parent, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, format, args)
		{
			this.Title     = MainClass.ApplicationName + " " + Catalog.GetString("Information");
			this.UseMarkup = use_markup;
			this.Destroyed += h;
			this.Run();
			this.Destroy();
		}
	}
	
	public class InfoMessageNonModal
	{

		private static InfoMessageNonModal global_instance = null;
		
		private List<string> messages = new List<string>();
		private List<EventHandler> handlers = new List<EventHandler>();
		private List<DateTime> date_times = new List<DateTime>();
		private int current_message = 0;
			
		public delegate void CloseClickedHandler();

		[Widget] Gtk.Dialog info_message_dialog;
		[Widget] Gtk.Button prev_button;
		[Widget] Gtk.Button next_button;
		[Widget] Gtk.Button info_ok_button;
		[Widget] Gtk.Button info_close_button;
		
		[Widget] Gtk.Label message_label;
		[Widget] Gtk.Label message_info_label;
		
		
		
		public InfoMessageNonModal(Window parent, EventHandler h, string format, params object[] args)
		{
			this.InitializeDialog(parent);
			
			global_instance.messages.Add(string.Format(format, args));
			global_instance.handlers.Add(h);
			global_instance.date_times.Add(DateTime.Now);
			global_instance.current_message = global_instance.messages.Count-1;
			global_instance.Update();
			global_instance.info_message_dialog.ShowAll();
			global_instance.info_message_dialog.Present();
		}
		
		public InfoMessageNonModal(Window parent, string format, params object[] args)
			: this(parent, null, format, args)
		{
		}

		private void InitializeDialog(Window parent)
		{
			if (InfoMessageNonModal.global_instance != null)
				return;
			
			if (parent == null)
				parent = MainClass.MainWindow;
			
			InfoMessageNonModal.global_instance = this;
			
			Glade.XML gui;

			try
			{
				gui = new Glade.XML(null, "GUI.UserInterface.glade", "info_message_dialog", MainClass.ApplicationDomain);
			}
			catch
			{
				Console.WriteLine("UserInterface: No embedded resource for GUI found. Trying to read external Glade file."); 
				gui = new Glade.XML("UserInterface.glade", "info_message_dialog", null);
			}
			gui.Autoconnect(this);
			
			if (MainClass.TouchScreen)
			{
				this.info_ok_button.HeightRequest    = MainClass.TouchScreenButtonSize;
				this.info_close_button.HeightRequest = MainClass.TouchScreenButtonSize;
				this.prev_button.HeightRequest       = MainClass.TouchScreenButtonSize;
				this.prev_button.WidthRequest        = MainClass.TouchScreenButtonSize;
				this.next_button.HeightRequest       = MainClass.TouchScreenButtonSize;
				this.next_button.WidthRequest        = MainClass.TouchScreenButtonSize;
			}
			
			this.info_message_dialog.TransientFor = parent;
			this.info_message_dialog.SetPosition(WindowPosition.Center);
			
			this.info_message_dialog.Title = MainClass.ApplicationName + " " + Catalog.GetString("Information");
			this.info_message_dialog.IconList = MainClass.QuickStepIcons;
			
			this.info_message_dialog.Destroyed += delegate {
				foreach (EventHandler handler in this.handlers)
				{
					if (handler != null)
						handler(this, EventArgs.Empty);
				}
				InfoMessageNonModal.global_instance = null; 
			};
		}
		
		private void Update()
		{
			this.prev_button.Sensitive = (this.current_message > 0);
			this.next_button.Sensitive = (this.current_message < this.messages.Count-1);
			
			this.message_info_label.Text = string.Format(Catalog.GetString("Message {0} of {1}"),
			                                             this.current_message+1,
			                                             this.messages.Count);
			this.message_label.Text = 
				"[" + this.date_times[this.current_message].ToString() + "]\n" +
				this.messages[this.current_message];
		}
		
		internal void OnOkButtonClicked(object o, EventArgs e)
		{
			if (this.messages.Count == 1)
			{
				this.info_message_dialog.Destroy();
				return;
			}
			
			if (this.handlers[this.current_message] != null)
				this.handlers[this.current_message](this, EventArgs.Empty);
			
			this.messages.RemoveAt(this.current_message);
			this.handlers.RemoveAt(this.current_message);
			
			if (this.current_message >= this.messages.Count)
				this.current_message = this.messages.Count-1;
			
			this.Update();
		}
		
		internal void OnCloseButtonClicked(object o, System.EventArgs e)
		{
			this.info_message_dialog.Destroy();
		}
		
		internal void OnLastButtonClicked(object o, EventArgs e)
		{
			--this.current_message;
			this.Update();
		}
		
		internal void OnNextButtonClicked(object o, EventArgs e)
		{
			++this.current_message;
			this.Update();
		}
		
		public static bool MessageIsShown
		{
			get { return InfoMessageNonModal.global_instance != null; }
		}
	}	

	public class ErrorMessage : Gtk.MessageDialog
	{

		private TextBuffer text_buffer;
		private bool run_dialog = true;
		
		
		public ErrorMessage(Window parent, Exception ex, string format, params object[] args)
			: base(parent, DialogFlags.Modal, MessageType.Error, ButtonsType.None, format, args)
		{
			this.Title    = MainClass.ApplicationName + " " + Catalog.GetString("Error");
			this.IconList = MainClass.QuickStepIcons;
			this.Resizable = true;
			
			this.AddButton(Stock.Copy,  0);
			this.AddButton(Stock.Close, 1);
			this.Response += new ResponseHandler(this.OnResponse);

			TextView view = new TextView();
			view.Editable = false;
			view.Buffer.Text  = "Operating system: " + MainClass.OS.ToString() + "\n";
			view.Buffer.Text += "Gtk Theme: " + Settings.Default.ThemeName + "\n";
            view.Buffer.Text += "Mono Runtime Version: " + MainClass.MonoVersionInfo + "\n";
			view.Buffer.Text += "Execution engine: " + System.Environment.Version + "\n";
			view.Buffer.Text += "QuickStep version: " + MainClass.Assembly.GetName().Version.ToString() + "\n";
			view.Buffer.Text += "Build date: " + MainClass.BuildDate + "\n";
			view.Buffer.Text += ex.ToString();
			view.Buffer.Text += "\nLoaded plug-ins:\n";
			if (MainWindow.UI != null)
				view.Buffer.Text += MainWindow.UI.GeneratePluginInfo();
			view.Buffer.SelectRange(view.Buffer.StartIter, view.Buffer.EndIter);
			view.HeightRequest = 150;
			
			this.text_buffer = view.Buffer;
			
			ScrolledWindow scrolled = new ScrolledWindow();
			scrolled.Add(view);
			
			Frame frame = new Frame();
			frame.Add(scrolled);
			
			this.VBox.PackStart(frame);
			
			this.ShowAll();
			
			while (this.run_dialog)
				this.Run();
			
			this.Destroy();
		}
		
		private void OnResponse(object o, ResponseArgs e)
		{
			switch ((int)e.ResponseId)
			{
				
			case 0:
				this.text_buffer.SelectRange(this.text_buffer.StartIter, this.text_buffer.EndIter);
				this.text_buffer.CopyClipboard(Clipboard.Get(Gdk.Selection.Clipboard));
				break;
				
			default:
				this.run_dialog = false;
				break;
				
			}
		}
	}
	
	public class ShortcutHintWindow : Gtk.Window
	{
		public ShortcutHintWindow(Window parent) : base(WindowType.Popup)
		{
			this.Title = Catalog.GetString("Define Shortcuts");
			
			VBox vbox = new VBox();
			
			Label l1 = new Label(Catalog.GetString("Define shortcuts by pressing a key (combination) while " +
			                                       "hovering with the mouse cursor over an active menu entry."));
			l1.Wrap = true;
			vbox.PackStart(l1);

			vbox.PackStart(new Image(MainClass.Assembly, "GUI.Icons.shortcuts_en.png"));
			
			Label l2 = new Label(Catalog.GetString("The shortcut will only be set if not already in use " + 
			                                       "by QuickStep. To remove shortcuts press the delete key."));
			l2.UseMarkup = true;
			l2.Wrap = true;
			vbox.PackStart(l2);
			
			Label l3 = new Label(Catalog.GetString("<b>Press Esc to exit edit mode.</b>"));
			l3.UseMarkup = true;
			vbox.PackStart(l3);
			
			vbox.Spacing = 5;
			this.Add(vbox);

			this.ModifyBg(StateType.Normal, new Gdk.Color(250, 250, 250));
			this.BorderWidth = 10;

			int x, y, w, h, d;
			parent.GdkWindow.GetGeometry(out x, out y, out w, out h, out d);

			this.ShowAll();
			this.Move(x+w/2-this.SizeRequest().Width/2,
			          y+h  -this.SizeRequest().Height-h/20);
		}
	}

    public class StatusMessage : Hiperscan.GtkExtensions.Widgets.RoundedWindow
	{
		public static int XOffset = 0;
		public static int YOffset = 0;
		public static volatile bool EnableMessages = false;
		
		private const int distance = 5;
		private static List<StatusMessage> instances = new List<StatusMessage>();
		
		
		public StatusMessage(Window parent, string text) : this(parent, text, false)
		{
		}
		
		public StatusMessage(Window parent, string text, bool warning) : base(10)
		{
			if (!StatusMessage.EnableMessages)
				return;
			
			if (parent == null || parent.GdkWindow == null)
				return;
			
			HBox hbox = new HBox();
			hbox.Spacing = 10;
			
			if (warning)
				hbox.PackStart(new Image(Stock.DialogWarning, IconSize.Dialog));
			else
				hbox.PackStart(new Image(Stock.DialogInfo, IconSize.Dialog));
				
			Label l = new Label(text);
			l.WidthRequest = 200;
			l.LineWrap = true;
			hbox.PackStart(l);
			
			this.Title = "Tooltip";
			this.Name  = "gtk-tooltips";
			this.BorderWidth = 10;

			this.Add(hbox);

			int x, y, w, h;
			parent.GetPosition(out x, out y);
			parent.GetSize(out w, out h);

			this.ShowAll();
			int ww, wh;
			this.GdkWindow.GetSize(out ww, out wh);
			this.HideAll();

			foreach (StatusMessage status_message in instances)
			{
				int root_x, root_y;
				status_message.GetPosition(out root_x, out root_y);
				status_message.Move(x + w - ww - XOffset, root_y - (wh + distance));
			}

			this.Move(x + w - ww - XOffset,  y + h - wh - YOffset);
			this.UpdateShape();

			this.ShowAll();
			UserInterface.ProcessEvents_();

			instances.Add(this);
			
			this.ButtonPressEvent += delegate(object o, ButtonPressEventArgs args) {
			};

			GLib.Timeout.Add(6000, delegate {
				instances.Remove(this);
				this.Destroy();
				return false;
			});
		}
		
		protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
		{
			instances.Remove(this);
			this.Destroy();
			return base.OnButtonPressEvent (evnt);
		}
	}
}
