using System;
using System.Collections.Generic;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class Case<TValue, TResult> : Producer<TResult, Case<TValue, TResult>._>, IEvaluatableObservable<TResult>
	{
		public Case(Func<TValue> selector, IDictionary<TValue, IObservable<TResult>> sources, IObservable<TResult> defaultSource)
		{
			this._selector = selector;
			this._sources = sources;
			this._defaultSource = defaultSource;
		}

		public IObservable<TResult> Eval()
		{
			IObservable<TResult> observable;
			if (this._sources.TryGetValue(this._selector(), out observable))
			{
				return observable;
			}
			return this._defaultSource;
		}

		protected override Case<TValue, TResult>._ CreateSink(IObserver<TResult> observer)
		{
			return new Case<TValue, TResult>._(observer);
		}

		protected override void Run(Case<TValue, TResult>._ sink)
		{
			sink.Run(this);
		}

		private readonly Func<TValue> _selector;

		private readonly IDictionary<TValue, IObservable<TResult>> _sources;

		private readonly IObservable<TResult> _defaultSource;

		internal sealed class _ : IdentitySink<TResult>
		{
			public _(IObserver<TResult> observer)
				: base(observer)
			{
			}

			public void Run(Case<TValue, TResult> parent)
			{
				IObservable<TResult> observable;
				try
				{
					observable = parent.Eval();
				}
				catch (Exception ex)
				{
					base.ForwardOnError(ex);
					return;
				}
				this.Run(observable);
			}
		}
	}
}
