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

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class AmbCoordinator<T> : IDisposable
	{
		internal AmbCoordinator(IObserver<T> downstream, int n)
		{
			this._downstream = downstream;
			AmbCoordinator<T>.InnerObserver[] array = new AmbCoordinator<T>.InnerObserver[n];
			for (int i = 0; i < n; i++)
			{
				array[i] = new AmbCoordinator<T>.InnerObserver(this, i);
			}
			this._observers = array;
			Volatile.Write(ref this._winner, -1);
		}

		internal static IDisposable Create(IObserver<T> observer, IObservable<T>[] sources)
		{
			int num = sources.Length;
			if (num == 0)
			{
				observer.OnCompleted();
				return Disposable.Empty;
			}
			if (num == 1)
			{
				return sources[0].Subscribe(observer);
			}
			AmbCoordinator<T> ambCoordinator = new AmbCoordinator<T>(observer, num);
			ambCoordinator.Subscribe(sources);
			return ambCoordinator;
		}

		internal void Subscribe(IObservable<T>[] sources)
		{
			for (int i = 0; i < this._observers.Length; i++)
			{
				AmbCoordinator<T>.InnerObserver innerObserver = Volatile.Read<AmbCoordinator<T>.InnerObserver>(ref this._observers[i]);
				if (innerObserver == null)
				{
					break;
				}
				innerObserver.Run(sources[i]);
			}
		}

		public void Dispose()
		{
			for (int i = 0; i < this._observers.Length; i++)
			{
				AmbCoordinator<T>.InnerObserver innerObserver = Interlocked.Exchange<AmbCoordinator<T>.InnerObserver>(ref this._observers[i], null);
				if (innerObserver != null)
				{
					innerObserver.Dispose();
				}
			}
		}

		private bool TryWin(int index)
		{
			if (Volatile.Read(ref this._winner) == -1 && Interlocked.CompareExchange(ref this._winner, index, -1) == -1)
			{
				for (int i = 0; i < this._observers.Length; i++)
				{
					if (index != i)
					{
						AmbCoordinator<T>.InnerObserver innerObserver = Interlocked.Exchange<AmbCoordinator<T>.InnerObserver>(ref this._observers[i], null);
						if (innerObserver != null)
						{
							innerObserver.Dispose();
						}
					}
				}
				return true;
			}
			return false;
		}

		private readonly IObserver<T> _downstream;

		private readonly AmbCoordinator<T>.InnerObserver[] _observers;

		private int _winner;

		internal sealed class InnerObserver : IdentitySink<T>
		{
			public InnerObserver(AmbCoordinator<T> parent, int index)
				: base(parent._downstream)
			{
				this._parent = parent;
				this._index = index;
			}

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

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

			public override void OnNext(T value)
			{
				if (this._won)
				{
					base.ForwardOnNext(value);
					return;
				}
				if (this._parent.TryWin(this._index))
				{
					this._won = true;
					base.ForwardOnNext(value);
					return;
				}
				base.Dispose();
			}

			private readonly AmbCoordinator<T> _parent;

			private readonly int _index;

			private bool _won;
		}
	}
}
