using System;
using System.Threading;

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

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

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

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

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

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

			public override bool TryMoveNext(out TSource current)
			{
				NotificationKind notificationKind = NotificationKind.OnNext;
				TSource tsource = default(TSource);
				Exception ex = null;
				this._semaphore.Wait();
				object gate = this._gate;
				lock (gate)
				{
					notificationKind = this._kind;
					if (notificationKind != NotificationKind.OnNext)
					{
						if (notificationKind == NotificationKind.OnError)
						{
							ex = this._error;
						}
					}
					else
					{
						tsource = this._value;
					}
					this._notificationAvailable = false;
				}
				switch (notificationKind)
				{
				case NotificationKind.OnNext:
					current = tsource;
					return true;
				case NotificationKind.OnError:
					ex.Throw();
					break;
				}
				current = default(TSource);
				return false;
			}

			private readonly object _gate;

			private readonly SemaphoreSlim _semaphore;

			private bool _notificationAvailable;

			private NotificationKind _kind;

			private TSource _value;

			private Exception _error;
		}
	}
}
