using System;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class ElementAt<TSource> : Producer<TSource, ElementAt<TSource>._>
	{
		public ElementAt(IObservable<TSource> source, int index)
		{
			this._source = source;
			this._index = index;
		}

		protected override ElementAt<TSource>._ CreateSink(IObserver<TSource> observer)
		{
			return new ElementAt<TSource>._(this._index, observer);
		}

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

		private readonly IObservable<TSource> _source;

		private readonly int _index;

		internal sealed class _ : IdentitySink<TSource>
		{
			public _(int index, IObserver<TSource> observer)
				: base(observer)
			{
				this._i = index;
			}

			public override void OnNext(TSource value)
			{
				if (this._i == 0)
				{
					base.ForwardOnNext(value);
					base.ForwardOnCompleted();
				}
				this._i--;
			}

			public override void OnCompleted()
			{
				if (this._i >= 0)
				{
					base.ForwardOnError(new ArgumentOutOfRangeException("index"));
				}
			}

			private int _i;
		}
	}
}
