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

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class Repeat<TResult>
	{
		internal sealed class ForeverRecursive : Producer<TResult, Repeat<TResult>.ForeverRecursive._>
		{
			public ForeverRecursive(TResult value, IScheduler scheduler)
			{
				this._value = value;
				this._scheduler = scheduler;
			}

			protected override Repeat<TResult>.ForeverRecursive._ CreateSink(IObserver<TResult> observer)
			{
				return new Repeat<TResult>.ForeverRecursive._(this._value, observer);
			}

			protected override void Run(Repeat<TResult>.ForeverRecursive._ sink)
			{
				sink.Run(this._scheduler);
			}

			private readonly TResult _value;

			private readonly IScheduler _scheduler;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(TResult value, IObserver<TResult> observer)
					: base(observer)
				{
					this._value = value;
				}

				public void Run(IScheduler scheduler)
				{
					IDisposable disposable = scheduler.Schedule<Repeat<TResult>.ForeverRecursive._>(this, (IScheduler innerScheduler, Repeat<TResult>.ForeverRecursive._ @this) => @this.LoopRecInf(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 LoopRecInf(IScheduler scheduler)
				{
					base.ForwardOnNext(this._value);
					IDisposable disposable = scheduler.Schedule<Repeat<TResult>.ForeverRecursive._>(this, (IScheduler innerScheduler, Repeat<TResult>.ForeverRecursive._ @this) => @this.LoopRecInf(innerScheduler));
					Disposable.TrySetMultiple(ref this._task, disposable);
					return Disposable.Empty;
				}

				private readonly TResult _value;

				private IDisposable _task;
			}
		}

		internal sealed class ForeverLongRunning : Producer<TResult, Repeat<TResult>.ForeverLongRunning._>
		{
			public ForeverLongRunning(TResult value, ISchedulerLongRunning scheduler)
			{
				this._value = value;
				this._scheduler = scheduler;
			}

			protected override Repeat<TResult>.ForeverLongRunning._ CreateSink(IObserver<TResult> observer)
			{
				return new Repeat<TResult>.ForeverLongRunning._(this._value, observer);
			}

			protected override void Run(Repeat<TResult>.ForeverLongRunning._ sink)
			{
				sink.Run(this._scheduler);
			}

			private readonly TResult _value;

			private readonly ISchedulerLongRunning _scheduler;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(TResult value, IObserver<TResult> observer)
					: base(observer)
				{
					this._value = value;
				}

				public void Run(ISchedulerLongRunning longRunning)
				{
					base.SetUpstream(longRunning.ScheduleLongRunning<Repeat<TResult>.ForeverLongRunning._>(this, delegate(Repeat<TResult>.ForeverLongRunning._ @this, ICancelable c)
					{
						@this.LoopInf(c);
					}));
				}

				private void LoopInf(ICancelable cancel)
				{
					TResult value = this._value;
					while (!cancel.IsDisposed)
					{
						base.ForwardOnNext(value);
					}
					base.Dispose();
				}

				private readonly TResult _value;
			}
		}

		internal sealed class CountRecursive : Producer<TResult, Repeat<TResult>.CountRecursive._>
		{
			public CountRecursive(TResult value, int repeatCount, IScheduler scheduler)
			{
				this._value = value;
				this._scheduler = scheduler;
				this._repeatCount = repeatCount;
			}

			protected override Repeat<TResult>.CountRecursive._ CreateSink(IObserver<TResult> observer)
			{
				return new Repeat<TResult>.CountRecursive._(this._value, this._repeatCount, observer);
			}

			protected override void Run(Repeat<TResult>.CountRecursive._ sink)
			{
				sink.Run(this._scheduler);
			}

			private readonly TResult _value;

			private readonly IScheduler _scheduler;

			private readonly int _repeatCount;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(TResult value, int repeatCount, IObserver<TResult> observer)
					: base(observer)
				{
					this._value = value;
					this._remaining = repeatCount;
				}

				public void Run(IScheduler scheduler)
				{
					IDisposable disposable = scheduler.Schedule<Repeat<TResult>.CountRecursive._>(this, (IScheduler innerScheduler, Repeat<TResult>.CountRecursive._ @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 num = this._remaining;
					if (num > 0)
					{
						base.ForwardOnNext(this._value);
						num = (this._remaining = num - 1);
					}
					if (num == 0)
					{
						base.ForwardOnCompleted();
					}
					else
					{
						IDisposable disposable = scheduler.Schedule<Repeat<TResult>.CountRecursive._>(this, (IScheduler innerScheduler, Repeat<TResult>.CountRecursive._ @this) => @this.LoopRec(innerScheduler));
						Disposable.TrySetMultiple(ref this._task, disposable);
					}
					return Disposable.Empty;
				}

				private readonly TResult _value;

				private int _remaining;

				private IDisposable _task;
			}
		}

		internal sealed class CountLongRunning : Producer<TResult, Repeat<TResult>.CountLongRunning._>
		{
			public CountLongRunning(TResult value, int repeatCount, ISchedulerLongRunning scheduler)
			{
				this._value = value;
				this._scheduler = scheduler;
				this._repeatCount = repeatCount;
			}

			protected override Repeat<TResult>.CountLongRunning._ CreateSink(IObserver<TResult> observer)
			{
				return new Repeat<TResult>.CountLongRunning._(this._value, this._repeatCount, observer);
			}

			protected override void Run(Repeat<TResult>.CountLongRunning._ sink)
			{
				sink.Run(this._scheduler);
			}

			private readonly TResult _value;

			private readonly ISchedulerLongRunning _scheduler;

			private readonly int _repeatCount;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(TResult value, int remaining, IObserver<TResult> observer)
					: base(observer)
				{
					this._value = value;
					this._remaining = remaining;
				}

				public void Run(ISchedulerLongRunning longRunning)
				{
					base.SetUpstream(longRunning.ScheduleLongRunning<Repeat<TResult>.CountLongRunning._>(this, delegate(Repeat<TResult>.CountLongRunning._ @this, ICancelable cancel)
					{
						@this.Loop(cancel);
					}));
				}

				private void Loop(ICancelable cancel)
				{
					TResult value = this._value;
					int num = this._remaining;
					while (num > 0 && !cancel.IsDisposed)
					{
						base.ForwardOnNext(value);
						num--;
					}
					if (!cancel.IsDisposed)
					{
						base.ForwardOnCompleted();
					}
				}

				private readonly TResult _value;

				private readonly int _remaining;
			}
		}
	}
}
