using System;
using System.Reactive.Disposables;
using System.Threading;
using System.Windows.Forms;

namespace System.Reactive.Concurrency
{
	public class ControlScheduler : LocalScheduler, GInterface7
	{
		public ControlScheduler(Control control)
		{
			if (control == null)
			{
				throw new ArgumentNullException("control");
			}
			this._control = control;
		}

		public Control Control
		{
			get
			{
				return this._control;
			}
		}

		public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			if (this._control.IsDisposed)
			{
				return Disposable.Empty;
			}
			SingleAssignmentDisposable d = new SingleAssignmentDisposable();
			this._control.BeginInvoke(new Action(delegate
			{
				if (!this._control.IsDisposed && !d.IsDisposed)
				{
					d.Disposable = action(this, state);
				}
			}));
			return d;
		}

		public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			TimeSpan dt = Scheduler.Normalize(dueTime);
			if (dt.Ticks == 0L)
			{
				return this.Schedule<TState>(state, action);
			}
			Func<IScheduler, TState, IDisposable> func = delegate(IScheduler scheduler1, TState state1)
			{
				MultipleAssignmentDisposable d = new MultipleAssignmentDisposable();
				global::System.Windows.Forms.Timer timer = new global::System.Windows.Forms.Timer();
				timer.Tick += delegate(object sender, EventArgs e)
				{
					global::System.Windows.Forms.Timer timer3 = Interlocked.Exchange<global::System.Windows.Forms.Timer>(ref timer, null);
					if (timer3 != null)
					{
						try
						{
							if (!this._control.IsDisposed && !d.IsDisposed)
							{
								d.Disposable = action(scheduler1, state1);
							}
						}
						finally
						{
							timer3.Stop();
							action = null;
						}
					}
				};
				timer.Interval = (int)dt.TotalMilliseconds;
				timer.Start();
				d.Disposable = Disposable.Create(delegate
				{
					global::System.Windows.Forms.Timer timer2 = Interlocked.Exchange<global::System.Windows.Forms.Timer>(ref timer, null);
					if (timer2 != null)
					{
						timer2.Stop();
						action = (IScheduler _, TState __) => Disposable.Empty;
					}
				});
				return d;
			};
			if (this._control.InvokeRequired)
			{
				return this.Schedule<TState>(state, func);
			}
			return func(this, state);
		}

		public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
		{
			if (period.TotalMilliseconds < 1.0)
			{
				throw new ArgumentOutOfRangeException("period");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			Func<IScheduler, TState, IDisposable> func = delegate(IScheduler scheduler1, TState state1)
			{
				global::System.Windows.Forms.Timer timer = new global::System.Windows.Forms.Timer();
				timer.Tick += delegate(object sender, EventArgs e)
				{
					if (!this._control.IsDisposed)
					{
						state1 = action(state1);
					}
				};
				timer.Interval = (int)period.TotalMilliseconds;
				timer.Start();
				return Disposable.Create(delegate
				{
					global::System.Windows.Forms.Timer timer2 = Interlocked.Exchange<global::System.Windows.Forms.Timer>(ref timer, null);
					if (timer2 != null)
					{
						timer2.Stop();
						action = (TState _) => _;
					}
				});
			};
			if (this._control.InvokeRequired)
			{
				return this.Schedule<TState>(state, func);
			}
			return func(this, state);
		}

		private readonly Control _control;
	}
}
