using System;
using System.Threading;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class Amb<TSource> : Producer<TSource, Amb<TSource>.AmbCoordinator>
	{
		public Amb(IObservable<TSource> left, IObservable<TSource> right)
		{
			this._left = left;
			this._right = right;
		}

		protected override Amb<TSource>.AmbCoordinator CreateSink(IObserver<TSource> observer)
		{
			return new Amb<TSource>.AmbCoordinator(observer);
		}

		protected override void Run(Amb<TSource>.AmbCoordinator sink)
		{
			sink.Run(this._left, this._right);
		}

		private readonly IObservable<TSource> _left;

		private readonly IObservable<TSource> _right;

		internal sealed class AmbCoordinator : IDisposable
		{
			public AmbCoordinator(IObserver<TSource> observer)
			{
				this._leftObserver = new Amb<TSource>.AmbCoordinator.AmbObserver(observer, this, true);
				this._rightObserver = new Amb<TSource>.AmbCoordinator.AmbObserver(observer, this, false);
			}

			public void Run(IObservable<TSource> left, IObservable<TSource> right)
			{
				this._leftObserver.Run(left);
				this._rightObserver.Run(right);
			}

			public void Dispose()
			{
				this._leftObserver.Dispose();
				this._rightObserver.Dispose();
			}

			public bool TryWin(bool isLeft)
			{
				int num = (isLeft ? 1 : 2);
				if (Volatile.Read(ref this._winner) == num)
				{
					return true;
				}
				if (Interlocked.CompareExchange(ref this._winner, num, 0) == 0)
				{
					(isLeft ? this._rightObserver : this._leftObserver).Dispose();
					return true;
				}
				return false;
			}

			private readonly Amb<TSource>.AmbCoordinator.AmbObserver _leftObserver;

			private readonly Amb<TSource>.AmbCoordinator.AmbObserver _rightObserver;

			private int _winner;

			private sealed class AmbObserver : IdentitySink<TSource>
			{
				public AmbObserver(IObserver<TSource> downstream, Amb<TSource>.AmbCoordinator parent, bool isLeft)
					: base(downstream)
				{
					this._parent = parent;
					this._isLeft = isLeft;
				}

				public override void OnCompleted()
				{
					if (this._iwon)
					{
						base.ForwardOnCompleted();
						return;
					}
					if (this._parent.TryWin(this._isLeft))
					{
						this._iwon = true;
						base.ForwardOnCompleted();
						return;
					}
					base.Dispose();
				}

				public override void OnError(Exception error)
				{
					if (this._iwon)
					{
						base.ForwardOnError(error);
						return;
					}
					if (this._parent.TryWin(this._isLeft))
					{
						this._iwon = true;
						base.ForwardOnError(error);
						return;
					}
					base.Dispose();
				}

				public override void OnNext(TSource value)
				{
					if (this._iwon)
					{
						base.ForwardOnNext(value);
						return;
					}
					if (this._parent.TryWin(this._isLeft))
					{
						this._iwon = true;
						base.ForwardOnNext(value);
					}
				}

				private readonly Amb<TSource>.AmbCoordinator _parent;

				private readonly bool _isLeft;

				private bool _iwon;
			}
		}
	}
}
