using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class RangeRecursive : Producer<int, RangeRecursive.RangeSink>
	{
		public RangeRecursive(int start, int count, IScheduler scheduler)
		{
			this._start = start;
			this._count = count;
			this._scheduler = scheduler;
		}

		protected override RangeRecursive.RangeSink CreateSink(IObserver<int> observer)
		{
			return new RangeRecursive.RangeSink(this._start, this._count, observer);
		}

		protected override void Run(RangeRecursive.RangeSink sink)
		{
			sink.Run(this._scheduler);
		}

		private readonly int _start;

		private readonly int _count;

		private readonly IScheduler _scheduler;

		internal sealed class RangeSink : IdentitySink<int>
		{
			public RangeSink(int start, int count, IObserver<int> observer)
				: base(observer)
			{
				this._index = start;
				this._end = start + count;
			}

			public void Run(IScheduler scheduler)
			{
				IDisposable disposable = scheduler.Schedule<RangeRecursive.RangeSink>(this, (IScheduler innerScheduler, RangeRecursive.RangeSink @this) => @this.LoopRec(innerScheduler));
				Disposable.TrySetSingle(ref this._task, disposable);
			}

			protected override void Dispose(bool disposing)
			{
				base.Dispose(disposing);
				if (disposing)
				{
					Disposable.TryDispose(ref this._task);
				}
			}

			private IDisposable LoopRec(IScheduler scheduler)
			{
				int index = this._index;
				if (index != this._end)
				{
					this._index = index + 1;
					base.ForwardOnNext(index);
					IDisposable disposable = scheduler.Schedule<RangeRecursive.RangeSink>(this, (IScheduler innerScheduler, RangeRecursive.RangeSink @this) => @this.LoopRec(innerScheduler));
					Disposable.TrySetMultiple(ref this._task, disposable);
				}
				else
				{
					base.ForwardOnCompleted();
				}
				return Disposable.Empty;
			}

			private readonly int _end;

			private int _index;

			private IDisposable _task;
		}
	}
}
