using System;
using System.Collections.Generic;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class Catch<TSource> : Producer<TSource, Catch<TSource>._>
	{
		public Catch(IEnumerable<IObservable<TSource>> sources)
		{
			this._sources = sources;
		}

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

		protected override void Run(Catch<TSource>._ sink)
		{
			sink.Run(this._sources);
		}

		private readonly IEnumerable<IObservable<TSource>> _sources;

		internal sealed class _ : TailRecursiveSink<TSource>
		{
			public _(IObserver<TSource> observer)
				: base(observer)
			{
			}

			protected override IEnumerable<IObservable<TSource>> Extract(IObservable<TSource> source)
			{
				Catch<TSource> @catch = source as Catch<TSource>;
				if (@catch != null)
				{
					return @catch._sources;
				}
				return null;
			}

			public override void OnError(Exception error)
			{
				this._lastException = error;
				base.Recurse();
			}

			protected override void Done()
			{
				if (this._lastException != null)
				{
					base.ForwardOnError(this._lastException);
					return;
				}
				base.ForwardOnCompleted();
			}

			protected override bool Fail(Exception error)
			{
				this.OnError(error);
				return true;
			}

			private Exception _lastException;
		}
	}
}
