using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class SelectMany<TSource, T, TResult>
	{
		internal sealed class ObservableSelector : Producer<TResult, SelectMany<TSource, T, TResult>.ObservableSelector._>
		{
			public ObservableSelector(IObservable<TSource> source, Func<TSource, IObservable<T>> collectionSelector, Func<TSource, T, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.ObservableSelector._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.ObservableSelector._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.ObservableSelector._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, IObservable<T>> _collectionSelector;

			private readonly Func<TSource, T, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.ObservableSelector parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void OnNext(TSource value)
				{
					IObservable<T> observable = null;
					try
					{
						observable = this._collectionSelector(value);
					}
					catch (Exception ex)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnError(ex);
						}
						return;
					}
					SelectMany<TSource, T, TResult>.ObservableSelector._.InnerObserver innerObserver = new SelectMany<TSource, T, TResult>.ObservableSelector._.InnerObserver(this, value);
					this._group.Add(innerObserver);
					innerObserver.SetResource(observable.SubscribeSafe(innerObserver));
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					this._isStopped = true;
					if (this._group.Count == 0)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnCompleted();
							return;
						}
					}
					base.DisposeUpstream();
				}

				protected override void Dispose(bool disposing)
				{
					base.Dispose(disposing);
					if (disposing)
					{
						this._group.Dispose();
					}
				}

				private readonly object _gate = new object();

				private readonly CompositeDisposable _group = new CompositeDisposable();

				private readonly Func<TSource, IObservable<T>> _collectionSelector;

				private readonly Func<TSource, T, TResult> _resultSelector;

				private volatile bool _isStopped;

				private sealed class InnerObserver : SafeObserver<T>
				{
					public InnerObserver(SelectMany<TSource, T, TResult>.ObservableSelector._ parent, TSource value)
					{
						this._parent = parent;
						this._value = value;
					}

					public override void OnNext(T value)
					{
						TResult tresult;
						object obj;
						try
						{
							tresult = this._parent._resultSelector(this._value, value);
						}
						catch (Exception ex)
						{
							obj = this._parent._gate;
							lock (obj)
							{
								this._parent.ForwardOnError(ex);
							}
							return;
						}
						obj = this._parent._gate;
						lock (obj)
						{
							this._parent.ForwardOnNext(tresult);
						}
					}

					public override void OnError(Exception error)
					{
						object gate = this._parent._gate;
						lock (gate)
						{
							this._parent.ForwardOnError(error);
						}
					}

					public override void OnCompleted()
					{
						this._parent._group.Remove(this);
						if (this._parent._isStopped && this._parent._group.Count == 0)
						{
							object gate = this._parent._gate;
							lock (gate)
							{
								this._parent.ForwardOnCompleted();
							}
						}
					}

					private readonly SelectMany<TSource, T, TResult>.ObservableSelector._ _parent;

					private readonly TSource _value;
				}
			}
		}

		internal sealed class ObservableSelectorIndexed : Producer<TResult, SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._>
		{
			public ObservableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IObservable<T>> collectionSelector, Func<TSource, int, T, int, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, int, IObservable<T>> _collectionSelector;

			private readonly Func<TSource, int, T, int, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.ObservableSelectorIndexed parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void OnNext(TSource value)
				{
					int index = this._index;
					this._index = checked(index + 1);
					int num = index;
					IObservable<T> observable = null;
					try
					{
						observable = this._collectionSelector(value, num);
					}
					catch (Exception ex)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnError(ex);
						}
						return;
					}
					SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._.InnerObserver innerObserver = new SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._.InnerObserver(this, value, num);
					this._group.Add(innerObserver);
					innerObserver.SetResource(observable.SubscribeSafe(innerObserver));
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					this._isStopped = true;
					if (this._group.Count == 0)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnCompleted();
							return;
						}
					}
					base.DisposeUpstream();
				}

				protected override void Dispose(bool disposing)
				{
					base.Dispose(disposing);
					if (disposing)
					{
						this._group.Dispose();
					}
				}

				private readonly object _gate = new object();

				private readonly CompositeDisposable _group = new CompositeDisposable();

				private readonly Func<TSource, int, IObservable<T>> _collectionSelector;

				private readonly Func<TSource, int, T, int, TResult> _resultSelector;

				private volatile bool _isStopped;

				private int _index;

				private sealed class InnerObserver : SafeObserver<T>
				{
					public InnerObserver(SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._ parent, TSource value, int index)
					{
						this._parent = parent;
						this._value = value;
						this._valueIndex = index;
					}

					public override void OnNext(T value)
					{
						TResult tresult;
						object obj;
						try
						{
							Func<TSource, int, T, int, TResult> resultSelector = this._parent._resultSelector;
							TSource value2 = this._value;
							int valueIndex = this._valueIndex;
							int index = this._index;
							this._index = checked(index + 1);
							tresult = resultSelector(value2, valueIndex, value, index);
						}
						catch (Exception ex)
						{
							obj = this._parent._gate;
							lock (obj)
							{
								this._parent.ForwardOnError(ex);
							}
							return;
						}
						obj = this._parent._gate;
						lock (obj)
						{
							this._parent.ForwardOnNext(tresult);
						}
					}

					public override void OnError(Exception error)
					{
						object gate = this._parent._gate;
						lock (gate)
						{
							this._parent.ForwardOnError(error);
						}
					}

					public override void OnCompleted()
					{
						this._parent._group.Remove(this);
						if (this._parent._isStopped && this._parent._group.Count == 0)
						{
							object gate = this._parent._gate;
							lock (gate)
							{
								this._parent.ForwardOnCompleted();
							}
						}
					}

					private readonly SelectMany<TSource, T, TResult>.ObservableSelectorIndexed._ _parent;

					private readonly TSource _value;

					private readonly int _valueIndex;

					private int _index;
				}
			}
		}

		internal sealed class EnumerableSelector : Producer<TResult, SelectMany<TSource, T, TResult>.EnumerableSelector._>
		{
			public EnumerableSelector(IObservable<TSource> source, Func<TSource, IEnumerable<T>> collectionSelector, Func<TSource, T, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.EnumerableSelector._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.EnumerableSelector._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.EnumerableSelector._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, IEnumerable<T>> _collectionSelector;

			private readonly Func<TSource, T, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.EnumerableSelector parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void OnNext(TSource value)
				{
					IEnumerable<T> enumerable = null;
					try
					{
						enumerable = this._collectionSelector(value);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					IEnumerator<T> enumerator;
					try
					{
						enumerator = enumerable.GetEnumerator();
					}
					catch (Exception ex2)
					{
						base.ForwardOnError(ex2);
						return;
					}
					using (enumerator)
					{
						bool flag = true;
						while (flag)
						{
							TResult tresult = default(TResult);
							try
							{
								if (flag = enumerator.MoveNext())
								{
									tresult = this._resultSelector(value, enumerator.Current);
								}
							}
							catch (Exception ex3)
							{
								base.ForwardOnError(ex3);
								break;
							}
							if (flag)
							{
								base.ForwardOnNext(tresult);
							}
						}
					}
				}

				private readonly Func<TSource, IEnumerable<T>> _collectionSelector;

				private readonly Func<TSource, T, TResult> _resultSelector;
			}
		}

		internal sealed class EnumerableSelectorIndexed : Producer<TResult, SelectMany<TSource, T, TResult>.EnumerableSelectorIndexed._>
		{
			public EnumerableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IEnumerable<T>> collectionSelector, Func<TSource, int, T, int, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.EnumerableSelectorIndexed._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.EnumerableSelectorIndexed._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.EnumerableSelectorIndexed._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, int, IEnumerable<T>> _collectionSelector;

			private readonly Func<TSource, int, T, int, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.EnumerableSelectorIndexed parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void OnNext(TSource value)
				{
					int index = this._index;
					checked
					{
						this._index = index + 1;
						int num = index;
						IEnumerable<T> enumerable = null;
						try
						{
							enumerable = this._collectionSelector(value, num);
						}
						catch (Exception ex)
						{
							base.ForwardOnError(ex);
							return;
						}
						IEnumerator<T> enumerator;
						try
						{
							enumerator = enumerable.GetEnumerator();
						}
						catch (Exception ex2)
						{
							base.ForwardOnError(ex2);
							return;
						}
						using (enumerator)
						{
							int num2 = 0;
							bool flag = true;
							while (flag)
							{
								TResult tresult = default(TResult);
								try
								{
									if (flag = enumerator.MoveNext())
									{
										tresult = this._resultSelector(value, num, enumerator.Current, num2++);
									}
								}
								catch (Exception ex3)
								{
									base.ForwardOnError(ex3);
									break;
								}
								if (flag)
								{
									base.ForwardOnNext(tresult);
								}
							}
						}
					}
				}

				private readonly Func<TSource, int, IEnumerable<T>> _collectionSelector;

				private readonly Func<TSource, int, T, int, TResult> _resultSelector;

				private int _index;
			}
		}

		internal sealed class TaskSelector : Producer<TResult, SelectMany<TSource, T, TResult>.TaskSelector._>
		{
			public TaskSelector(IObservable<TSource> source, Func<TSource, CancellationToken, Task<T>> collectionSelector, Func<TSource, T, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.TaskSelector._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.TaskSelector._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.TaskSelector._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, CancellationToken, Task<T>> _collectionSelector;

			private readonly Func<TSource, T, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.TaskSelector parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void Run(IObservable<TSource> source)
				{
					this._count = 1;
					base.Run(source);
				}

				protected override void Dispose(bool disposing)
				{
					if (disposing)
					{
						this._cancel.Cancel();
					}
					base.Dispose(disposing);
				}

				public override void OnNext(TSource value)
				{
					Task<T> task = null;
					try
					{
						Interlocked.Increment(ref this._count);
						task = this._collectionSelector(value, this._cancel.Token);
					}
					catch (Exception ex)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnError(ex);
						}
						return;
					}
					if (task.IsCompleted)
					{
						this.OnCompletedTask(value, task);
						return;
					}
					task.ContinueWithState(delegate(Task<T> t, [TupleElementNames(new string[] { "this", "value" })] ValueTuple<SelectMany<TSource, T, TResult>.TaskSelector._, TSource> tuple)
					{
						tuple.Item1.OnCompletedTask(tuple.Item2, t);
					}, new ValueTuple<SelectMany<TSource, T, TResult>.TaskSelector._, TSource>(this, value), this._cancel.Token);
				}

				private void OnCompletedTask(TSource value, Task<T> task)
				{
					object obj;
					switch (task.Status)
					{
					case TaskStatus.RanToCompletion:
					{
						TResult tresult;
						try
						{
							tresult = this._resultSelector(value, task.Result);
						}
						catch (Exception ex)
						{
							obj = this._gate;
							lock (obj)
							{
								base.ForwardOnError(ex);
							}
							return;
						}
						obj = this._gate;
						lock (obj)
						{
							base.ForwardOnNext(tresult);
						}
						this.OnCompleted();
						return;
					}
					case TaskStatus.Canceled:
						if (this._cancel.IsCancellationRequested)
						{
							return;
						}
						obj = this._gate;
						lock (obj)
						{
							base.ForwardOnError(new TaskCanceledException(task));
							return;
						}
						break;
					case TaskStatus.Faulted:
						break;
					default:
						return;
					}
					obj = this._gate;
					lock (obj)
					{
						base.ForwardOnError(task.Exception.InnerException);
					}
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					if (Interlocked.Decrement(ref this._count) == 0)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnCompleted();
						}
					}
				}

				private readonly object _gate = new object();

				private readonly CancellationTokenSource _cancel = new CancellationTokenSource();

				private readonly Func<TSource, CancellationToken, Task<T>> _collectionSelector;

				private readonly Func<TSource, T, TResult> _resultSelector;

				private volatile int _count;
			}
		}

		internal sealed class TaskSelectorIndexed : Producer<TResult, SelectMany<TSource, T, TResult>.TaskSelectorIndexed._>
		{
			public TaskSelectorIndexed(IObservable<TSource> source, Func<TSource, int, CancellationToken, Task<T>> collectionSelector, Func<TSource, int, T, TResult> resultSelector)
			{
				this._source = source;
				this._collectionSelector = collectionSelector;
				this._resultSelector = resultSelector;
			}

			protected override SelectMany<TSource, T, TResult>.TaskSelectorIndexed._ CreateSink(IObserver<TResult> observer)
			{
				return new SelectMany<TSource, T, TResult>.TaskSelectorIndexed._(this, observer);
			}

			protected override void Run(SelectMany<TSource, T, TResult>.TaskSelectorIndexed._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Func<TSource, int, CancellationToken, Task<T>> _collectionSelector;

			private readonly Func<TSource, int, T, TResult> _resultSelector;

			internal sealed class _ : Sink<TSource, TResult>
			{
				public _(SelectMany<TSource, T, TResult>.TaskSelectorIndexed parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._collectionSelector = parent._collectionSelector;
					this._resultSelector = parent._resultSelector;
				}

				public override void Run(IObservable<TSource> source)
				{
					this._count = 1;
					base.Run(source);
				}

				protected override void Dispose(bool disposing)
				{
					if (disposing)
					{
						this._cancel.Cancel();
					}
					base.Dispose(disposing);
				}

				public override void OnNext(TSource value)
				{
					int index = this._index;
					this._index = checked(index + 1);
					int num = index;
					Task<T> task = null;
					try
					{
						Interlocked.Increment(ref this._count);
						task = this._collectionSelector(value, num, this._cancel.Token);
					}
					catch (Exception ex)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnError(ex);
						}
						return;
					}
					if (task.IsCompleted)
					{
						this.OnCompletedTask(value, num, task);
						return;
					}
					task.ContinueWithState(delegate(Task<T> t, [TupleElementNames(new string[] { "this", "value", "index" })] ValueTuple<SelectMany<TSource, T, TResult>.TaskSelectorIndexed._, TSource, int> tuple)
					{
						tuple.Item1.OnCompletedTask(tuple.Item2, tuple.Item3, t);
					}, new ValueTuple<SelectMany<TSource, T, TResult>.TaskSelectorIndexed._, TSource, int>(this, value, num), this._cancel.Token);
				}

				private void OnCompletedTask(TSource value, int index, Task<T> task)
				{
					object obj;
					switch (task.Status)
					{
					case TaskStatus.RanToCompletion:
					{
						TResult tresult;
						try
						{
							tresult = this._resultSelector(value, index, task.Result);
						}
						catch (Exception ex)
						{
							obj = this._gate;
							lock (obj)
							{
								base.ForwardOnError(ex);
							}
							return;
						}
						obj = this._gate;
						lock (obj)
						{
							base.ForwardOnNext(tresult);
						}
						this.OnCompleted();
						return;
					}
					case TaskStatus.Canceled:
						if (this._cancel.IsCancellationRequested)
						{
							return;
						}
						obj = this._gate;
						lock (obj)
						{
							base.ForwardOnError(new TaskCanceledException(task));
							return;
						}
						break;
					case TaskStatus.Faulted:
						break;
					default:
						return;
					}
					obj = this._gate;
					lock (obj)
					{
						base.ForwardOnError(task.Exception.InnerException);
					}
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					if (Interlocked.Decrement(ref this._count) == 0)
					{
						object gate = this._gate;
						lock (gate)
						{
							base.ForwardOnCompleted();
						}
					}
				}

				private readonly object _gate = new object();

				private readonly CancellationTokenSource _cancel = new CancellationTokenSource();

				private readonly Func<TSource, int, CancellationToken, Task<T>> _collectionSelector;

				private readonly Func<TSource, int, T, TResult> _resultSelector;

				private volatile int _count;

				private int _index;
			}
		}
	}
}
