using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;

namespace System.Reactive.Concurrency
{
	[EditorBrowsable(EditorBrowsableState.Never)]
	public sealed class SchedulerOperationAwaiter : INotifyCompletion
	{
		internal SchedulerOperationAwaiter(Func<Action, IDisposable> schedule, CancellationToken cancellationToken, bool postBackToOriginalContext)
		{
			this._schedule = schedule;
			this._cancellationToken = cancellationToken;
			this._postBackToOriginalContext = postBackToOriginalContext;
			if (cancellationToken.CanBeCanceled)
			{
				this._ctr = this._cancellationToken.Register(delegate(object @this)
				{
					((SchedulerOperationAwaiter)@this).Cancel();
				}, this);
			}
		}

		public bool IsCompleted
		{
			get
			{
				return this._cancellationToken.IsCancellationRequested;
			}
		}

		public void GetResult()
		{
			this._cancellationToken.ThrowIfCancellationRequested();
		}

		public void OnCompleted(Action continuation)
		{
			if (continuation == null)
			{
				throw new ArgumentNullException("continuation");
			}
			if (this._continuation != null)
			{
				throw new InvalidOperationException(Strings_Core.SCHEDULER_OPERATION_ALREADY_AWAITED);
			}
			if (this._postBackToOriginalContext)
			{
				SynchronizationContext ctx = SynchronizationContext.Current;
				if (ctx != null)
				{
					Action original = continuation;
					continuation = delegate
					{
						ctx.Post(delegate(object a)
						{
							((Action)a)();
						}, original);
					};
				}
			}
			int ran = 0;
			this._continuation = delegate
			{
				if (Interlocked.Exchange(ref ran, 1) == 0)
				{
					this._ctr.Dispose();
					continuation();
				}
			};
			this._work = this._schedule(this._continuation);
		}

		private void Cancel()
		{
			IDisposable work = this._work;
			if (work != null)
			{
				work.Dispose();
			}
			Action continuation = this._continuation;
			if (continuation == null)
			{
				return;
			}
			continuation();
		}

		private readonly Func<Action, IDisposable> _schedule;

		private readonly CancellationToken _cancellationToken;

		private readonly bool _postBackToOriginalContext;

		private readonly CancellationTokenRegistration _ctr;

		private volatile Action _continuation;

		private volatile IDisposable _work;
	}
}
