using System;
using System.Threading;

namespace FSpot {

	
	public class ProgressItem {
		public ProgressItem () {
			
		}
		
		public delegate void ChangedHandler (ProgressItem item);
		public event ChangedHandler Changed;

		double value;
		public double Value {
			get {
				lock (this) {
					return value;
				}
			}
			set {
				lock (this) {
					this.value = value;
					if (Changed != null)
						Changed (this);
				}
			}
		}
	}

	public class ThreadProgressDialog : Gtk.Dialog {
		FSpot.Delay delay;

		private Gtk.ProgressBar progress_bar;
		private Gtk.Label message_label;
		private Gtk.Button button;

		private Gtk.Button retry_button;
		private Gtk.Button skip_button;
		private Gtk.ResponseType error_response;
		private AutoResetEvent error_response_event;
		private AutoResetEvent error_response_ack_event;

		private Thread thread;

		public ThreadProgressDialog (Thread thread, int total) {
			/*
			if (parent_window)
				this.TransientFor = parent_window;

			*/
			this.Title = thread.Name;
			this.thread = thread;
			
			HasSeparator = false;
			BorderWidth = 6;
			SetDefaultSize (300, -1);
			
			message_label = new Gtk.Label (String.Empty);
			VBox.PackStart (message_label, true, true, 12);
			
			progress_bar = new Gtk.ProgressBar ();
			VBox.PackStart (progress_bar, true, true, 6);

			retry_button = new Gtk.Button (Mono.Unix.Catalog.GetString ("Retry"));
			retry_button.Clicked += new EventHandler (HandleRetryClicked);
			skip_button = new Gtk.Button (Mono.Unix.Catalog.GetString ("Skip"));
			skip_button.Clicked += new EventHandler (HandleSkipClicked);

			ActionArea.Add (retry_button);
			ActionArea.Add (skip_button);

			button_label = Gtk.Stock.Cancel;
			button = (Gtk.Button) AddButton (button_label, (int)Gtk.ResponseType.Cancel);
			
			delay = new Delay (new GLib.IdleHandler (HandleUpdate));

			Response += HandleResponse;
			Destroyed += HandleDestroy;
		}

		private string progress_text;
		public string ProgressText {
			get {
				return progress_text;
			}
			set {
				lock (this) {
					progress_text = value;
					delay.Start ();
				}
			}
		}

		private string button_label;
		public string ButtonLabel {
			get {
				return button_label;
			}			
			set {
				lock (this) {
					button_label = value;
					delay.Start ();
				}
			}
		}
		
		private string message;
		public string Message {
			get {
				return message;
			}
			set {
				lock (this) {
					message = value;
					delay.Start ();
				}
			}
		}
		
		private double fraction;
		public double Fraction {
			get {
				return Fraction;
			}
			set {
				lock (this) {
					fraction = value;
					delay.Start ();
				}
			}
		}

		private bool retry_skip;
		private bool RetrySkipVisible {
			set { 
				retry_skip = value;
				delay.Start ();
			} 
		}

		public bool PerformRetrySkip ()
		{
			error_response = Gtk.ResponseType.None;
			RetrySkipVisible = true;

			error_response_event = new AutoResetEvent (false);
			error_response_ack_event = new AutoResetEvent (false);
			error_response_event.WaitOne ();

			RetrySkipVisible = false;

			return (error_response == Gtk.ResponseType.Yes);
		}

		private void HandleResponse (object obj, Gtk.ResponseArgs args) {
			this.Destroy ();
		}

		private bool HandleUpdate ()
		{
			message_label.Text = message;
			progress_bar.Text = progress_text;
			progress_bar.Fraction = System.Math.Min (1.0, System.Math.Max (0.0, fraction));
			button.Label = button_label;
			retry_button.Visible = skip_button.Visible = retry_skip;

			return false;
		}

		private void HandleDestroy (object sender, EventArgs args)
		{
			delay.Stop ();
			if (thread.IsAlive) {
				thread.Abort ();
			}
		}

		private void HandleRetryClicked (object obj, EventArgs args)
		{
			error_response = Gtk.ResponseType.Yes;
			error_response_event.Set ();
		}

		private void HandleSkipClicked (object obj, EventArgs args)
		{
			error_response = Gtk.ResponseType.No;
			error_response_event.Set ();
		}

		public void Start () {
			ShowAll ();
			RetrySkipVisible = false;
			thread.Start ();
		}
	}
}
