using System;
using System.Threading;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class Next<TSource> : PushToPullAdapter<TSource, TSource>
	{
		public Next(IObservable<TSource> source)
			: base(source)
		{
		}

		protected override PushToPullSink<TSource, TSource> Run()
		{
			return new Next<TSource>._();
		}

		private sealed class _ : PushToPullSink<TSource, TSource>
		{
			public _()
			{
				this._gate = new object();
				this._semaphore = new SemaphoreSlim(0, 1);
			}

			public override void OnNext(TSource value)
			{
				object gate = this._gate;
				lock (gate)
				{
					if (this._waiting)
					{
						this._value = value;
						this._kind = NotificationKind.OnNext;
						this._semaphore.Release();
					}
					this._waiting = false;
				}
			}

			public override void OnError(Exception error)
			{
				base.Dispose();
				object gate = this._gate;
				lock (gate)
				{
					this._error = error;
					this._kind = NotificationKind.OnError;
					if (this._waiting)
					{
						this._semaphore.Release();
					}
					this._waiting = false;
				}
			}

			public override void OnCompleted()
			{
				base.Dispose();
				object gate = this._gate;
				lock (gate)
				{
					this._kind = NotificationKind.OnCompleted;
					if (this._waiting)
					{
						this._semaphore.Release();
					}
					this._waiting = false;
				}
			}

			public override bool TryMoveNext(out TSource current)
			{
				bool flag = false;
				object gate = this._gate;
				lock (gate)
				{
					this._waiting = true;
					flag = this._kind > NotificationKind.OnNext;
				}
				if (!flag)
				{
					this._semaphore.Wait();
				}
				switch (this._kind)
				{
				case NotificationKind.OnNext:
					current = this._value;
					return true;
				case NotificationKind.OnError:
					this._error.Throw();
					break;
				}
				current = default(TSource);
				return false;
			}

			private readonly object _gate;

			private readonly SemaphoreSlim _semaphore;

			private bool _waiting;

			private NotificationKind _kind;

			private TSource _value;

			private Exception _error;
		}
	}
}
