using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class Generate<TState, TResult>
	{
		internal sealed class NoTime : Producer<TResult, Generate<TState, TResult>.NoTime._>
		{
			public NoTime(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector, IScheduler scheduler)
			{
				this._initialState = initialState;
				this._condition = condition;
				this._iterate = iterate;
				this._resultSelector = resultSelector;
				this._scheduler = scheduler;
			}

			protected override Generate<TState, TResult>.NoTime._ CreateSink(IObserver<TResult> observer)
			{
				return new Generate<TState, TResult>.NoTime._(this, observer);
			}

			protected override void Run(Generate<TState, TResult>.NoTime._ sink)
			{
				sink.Run(this._scheduler);
			}

			private readonly TState _initialState;

			private readonly Func<TState, bool> _condition;

			private readonly Func<TState, TState> _iterate;

			private readonly Func<TState, TResult> _resultSelector;

			private readonly IScheduler _scheduler;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(Generate<TState, TResult>.NoTime parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._condition = parent._condition;
					this._iterate = parent._iterate;
					this._resultSelector = parent._resultSelector;
					this._state = parent._initialState;
					this._first = true;
				}

				public void Run(IScheduler _scheduler)
				{
					ISchedulerLongRunning schedulerLongRunning = _scheduler.AsLongRunning();
					if (schedulerLongRunning != null)
					{
						base.SetUpstream(schedulerLongRunning.ScheduleLongRunning<Generate<TState, TResult>.NoTime._>(this, delegate(Generate<TState, TResult>.NoTime._ @this, ICancelable c)
						{
							@this.Loop(c);
						}));
						return;
					}
					base.SetUpstream(_scheduler.Schedule(this, delegate(Generate<TState, TResult>.NoTime._ @this, Action<Generate<TState, TResult>.NoTime._> a)
					{
						@this.LoopRec(a);
					}));
				}

				private void Loop(ICancelable cancel)
				{
					while (!cancel.IsDisposed)
					{
						bool flag = false;
						TResult tresult = default(TResult);
						try
						{
							if (this._first)
							{
								this._first = false;
							}
							else
							{
								this._state = this._iterate(this._state);
							}
							if (flag = this._condition(this._state))
							{
								tresult = this._resultSelector(this._state);
							}
						}
						catch (Exception ex)
						{
							base.ForwardOnError(ex);
							return;
						}
						if (flag)
						{
							base.ForwardOnNext(tresult);
							continue;
						}
						break;
					}
					if (!cancel.IsDisposed)
					{
						base.ForwardOnCompleted();
						return;
					}
				}

				private void LoopRec(Action<Generate<TState, TResult>.NoTime._> recurse)
				{
					bool flag = false;
					TResult tresult = default(TResult);
					try
					{
						if (this._first)
						{
							this._first = false;
						}
						else
						{
							this._state = this._iterate(this._state);
						}
						if (flag = this._condition(this._state))
						{
							tresult = this._resultSelector(this._state);
						}
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					if (flag)
					{
						base.ForwardOnNext(tresult);
						recurse(this);
						return;
					}
					base.ForwardOnCompleted();
				}

				private readonly Func<TState, bool> _condition;

				private readonly Func<TState, TState> _iterate;

				private readonly Func<TState, TResult> _resultSelector;

				private TState _state;

				private bool _first;
			}
		}

		internal sealed class Absolute : Producer<TResult, Generate<TState, TResult>.Absolute._>
		{
			public Absolute(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector, Func<TState, DateTimeOffset> timeSelector, IScheduler scheduler)
			{
				this._initialState = initialState;
				this._condition = condition;
				this._iterate = iterate;
				this._resultSelector = resultSelector;
				this._timeSelector = timeSelector;
				this._scheduler = scheduler;
			}

			protected override Generate<TState, TResult>.Absolute._ CreateSink(IObserver<TResult> observer)
			{
				return new Generate<TState, TResult>.Absolute._(this, observer);
			}

			protected override void Run(Generate<TState, TResult>.Absolute._ sink)
			{
				sink.Run(this._scheduler, this._initialState);
			}

			private readonly TState _initialState;

			private readonly Func<TState, bool> _condition;

			private readonly Func<TState, TState> _iterate;

			private readonly Func<TState, TResult> _resultSelector;

			private readonly Func<TState, DateTimeOffset> _timeSelector;

			private readonly IScheduler _scheduler;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(Generate<TState, TResult>.Absolute parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._condition = parent._condition;
					this._iterate = parent._iterate;
					this._resultSelector = parent._resultSelector;
					this._timeSelector = parent._timeSelector;
					this._first = true;
				}

				public void Run(IScheduler outerScheduler, TState initialState)
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetMultiple(ref this._timerDisposable, singleAssignmentDisposable);
					singleAssignmentDisposable.Disposable = outerScheduler.Schedule<ValueTuple<Generate<TState, TResult>.Absolute._, TState>>(new ValueTuple<Generate<TState, TResult>.Absolute._, TState>(this, initialState), (IScheduler scheduler, [TupleElementNames(new string[] { "this", "initialState" })] ValueTuple<Generate<TState, TResult>.Absolute._, TState> tuple) => tuple.Item1.InvokeRec(scheduler, tuple.Item2));
				}

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

				private IDisposable InvokeRec(IScheduler self, TState state)
				{
					DateTimeOffset dateTimeOffset = default(DateTimeOffset);
					if (this._hasResult)
					{
						base.ForwardOnNext(this._result);
					}
					IDisposable empty;
					try
					{
						if (this._first)
						{
							this._first = false;
						}
						else
						{
							state = this._iterate(state);
						}
						this._hasResult = this._condition(state);
						if (this._hasResult)
						{
							this._result = this._resultSelector(state);
							dateTimeOffset = this._timeSelector(state);
						}
						goto IL_0089;
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						empty = Disposable.Empty;
					}
					return empty;
					IL_0089:
					if (!this._hasResult)
					{
						base.ForwardOnCompleted();
						return Disposable.Empty;
					}
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetMultiple(ref this._timerDisposable, singleAssignmentDisposable);
					singleAssignmentDisposable.Disposable = self.Schedule<ValueTuple<Generate<TState, TResult>.Absolute._, TState>>(new ValueTuple<Generate<TState, TResult>.Absolute._, TState>(this, state), dateTimeOffset, (IScheduler scheduler, [TupleElementNames(new string[] { "this", "state" })] ValueTuple<Generate<TState, TResult>.Absolute._, TState> tuple) => tuple.Item1.InvokeRec(scheduler, tuple.Item2));
					return Disposable.Empty;
				}

				private readonly Func<TState, bool> _condition;

				private readonly Func<TState, TState> _iterate;

				private readonly Func<TState, TResult> _resultSelector;

				private readonly Func<TState, DateTimeOffset> _timeSelector;

				private bool _first;

				private bool _hasResult;

				private TResult _result;

				private IDisposable _timerDisposable;
			}
		}

		internal sealed class Relative : Producer<TResult, Generate<TState, TResult>.Relative._>
		{
			public Relative(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector, Func<TState, TimeSpan> timeSelector, IScheduler scheduler)
			{
				this._initialState = initialState;
				this._condition = condition;
				this._iterate = iterate;
				this._resultSelector = resultSelector;
				this._timeSelector = timeSelector;
				this._scheduler = scheduler;
			}

			protected override Generate<TState, TResult>.Relative._ CreateSink(IObserver<TResult> observer)
			{
				return new Generate<TState, TResult>.Relative._(this, observer);
			}

			protected override void Run(Generate<TState, TResult>.Relative._ sink)
			{
				sink.Run(this._scheduler, this._initialState);
			}

			private readonly TState _initialState;

			private readonly Func<TState, bool> _condition;

			private readonly Func<TState, TState> _iterate;

			private readonly Func<TState, TResult> _resultSelector;

			private readonly Func<TState, TimeSpan> _timeSelector;

			private readonly IScheduler _scheduler;

			internal sealed class _ : IdentitySink<TResult>
			{
				public _(Generate<TState, TResult>.Relative parent, IObserver<TResult> observer)
					: base(observer)
				{
					this._condition = parent._condition;
					this._iterate = parent._iterate;
					this._resultSelector = parent._resultSelector;
					this._timeSelector = parent._timeSelector;
					this._first = true;
				}

				public void Run(IScheduler outerScheduler, TState initialState)
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetMultiple(ref this._timerDisposable, singleAssignmentDisposable);
					singleAssignmentDisposable.Disposable = outerScheduler.Schedule<ValueTuple<Generate<TState, TResult>.Relative._, TState>>(new ValueTuple<Generate<TState, TResult>.Relative._, TState>(this, initialState), (IScheduler scheduler, [TupleElementNames(new string[] { "this", "initialState" })] ValueTuple<Generate<TState, TResult>.Relative._, TState> tuple) => tuple.Item1.InvokeRec(scheduler, tuple.Item2));
				}

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

				private IDisposable InvokeRec(IScheduler self, TState state)
				{
					TimeSpan timeSpan = default(TimeSpan);
					if (this._hasResult)
					{
						base.ForwardOnNext(this._result);
					}
					IDisposable empty;
					try
					{
						if (this._first)
						{
							this._first = false;
						}
						else
						{
							state = this._iterate(state);
						}
						this._hasResult = this._condition(state);
						if (this._hasResult)
						{
							this._result = this._resultSelector(state);
							timeSpan = this._timeSelector(state);
						}
						goto IL_0089;
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						empty = Disposable.Empty;
					}
					return empty;
					IL_0089:
					if (!this._hasResult)
					{
						base.ForwardOnCompleted();
						return Disposable.Empty;
					}
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetMultiple(ref this._timerDisposable, singleAssignmentDisposable);
					singleAssignmentDisposable.Disposable = self.Schedule<ValueTuple<Generate<TState, TResult>.Relative._, TState>>(new ValueTuple<Generate<TState, TResult>.Relative._, TState>(this, state), timeSpan, (IScheduler scheduler, [TupleElementNames(new string[] { "this", "state" })] ValueTuple<Generate<TState, TResult>.Relative._, TState> tuple) => tuple.Item1.InvokeRec(scheduler, tuple.Item2));
					return Disposable.Empty;
				}

				private readonly Func<TState, bool> _condition;

				private readonly Func<TState, TState> _iterate;

				private readonly Func<TState, TResult> _resultSelector;

				private readonly Func<TState, TimeSpan> _timeSelector;

				private bool _first;

				private bool _hasResult;

				private TResult _result;

				private IDisposable _timerDisposable;
			}
		}
	}
}
