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

namespace System.Reactive.Concurrency
{
	public class DispatcherScheduler : LocalScheduler, GInterface7
	{
		[Obsolete("Use the Current property to retrieve the DispatcherScheduler instance for the current thread's Dispatcher object.")]
		public static DispatcherScheduler Instance
		{
			get
			{
				return new DispatcherScheduler(Dispatcher.CurrentDispatcher);
			}
		}

		public static DispatcherScheduler Current
		{
			get
			{
				Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
				if (dispatcher == null)
				{
					throw new InvalidOperationException(Strings_WindowsThreading.NO_DISPATCHER_CURRENT_THREAD);
				}
				return new DispatcherScheduler(dispatcher);
			}
		}

		public DispatcherScheduler(Dispatcher dispatcher)
		{
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			this.Dispatcher = dispatcher;
			this.Priority = DispatcherPriority.Normal;
		}

		public DispatcherScheduler(Dispatcher dispatcher, DispatcherPriority priority)
		{
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			this.Dispatcher = dispatcher;
			this.Priority = priority;
		}

		public Dispatcher Dispatcher { get; }

		public DispatcherPriority Priority { get; }

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

		public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			TimeSpan timeSpan = Scheduler.Normalize(dueTime);
			if (timeSpan.Ticks == 0L)
			{
				return this.Schedule<TState>(state, action);
			}
			return this.ScheduleSlow<TState>(state, timeSpan, action);
		}

		private IDisposable ScheduleSlow<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
		{
			MultipleAssignmentDisposable d = new MultipleAssignmentDisposable();
			DispatcherTimer timer = new DispatcherTimer(this.Priority, this.Dispatcher);
			timer.Tick += delegate(object sender, EventArgs e)
			{
				DispatcherTimer dispatcherTimer = Interlocked.Exchange<DispatcherTimer>(ref timer, null);
				if (dispatcherTimer != null)
				{
					try
					{
						d.Disposable = action(this, state);
					}
					finally
					{
						dispatcherTimer.Stop();
						action = null;
					}
				}
			};
			timer.Interval = dueTime;
			timer.Start();
			d.Disposable = Disposable.Create(delegate
			{
				DispatcherTimer dispatcherTimer2 = Interlocked.Exchange<DispatcherTimer>(ref timer, null);
				if (dispatcherTimer2 != null)
				{
					dispatcherTimer2.Stop();
					action = (IScheduler _, TState __) => Disposable.Empty;
				}
			});
			return d;
		}

		public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
		{
			if (period < TimeSpan.Zero)
			{
				throw new ArgumentOutOfRangeException("period");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			DispatcherTimer timer = new DispatcherTimer(this.Priority, this.Dispatcher);
			TState state1 = state;
			timer.Tick += delegate(object sender, EventArgs e)
			{
				state1 = action(state1);
			};
			timer.Interval = period;
			timer.Start();
			return Disposable.Create(delegate
			{
				DispatcherTimer dispatcherTimer = Interlocked.Exchange<DispatcherTimer>(ref timer, null);
				if (dispatcherTimer != null)
				{
					dispatcherTimer.Stop();
					action = (TState _) => _;
				}
			});
		}
	}
}
