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

namespace System.Reactive.Concurrency
{
	internal sealed class CatchScheduler<T> : SchedulerWrapper where T : Exception
	{
		public CatchScheduler(IScheduler scheduler, Func<T, bool> handler)
			: base(scheduler)
		{
			this._handler = handler;
		}

		protected override Func<IScheduler, TState, IDisposable> Wrap<TState>(Func<IScheduler, TState, IDisposable> action)
		{
			return delegate(IScheduler self, TState state)
			{
				IDisposable disposable;
				object obj;
				T t;
				bool flag;
				T t2;
				try
				{
					disposable = action(this.GetRecursiveWrapper(self), state);
				}
				catch when (delegate
				{
					// Failed to create a 'catch-when' expression
					t = obj as T;
					if (t == null)
					{
						flag = false;
					}
					else
					{
						t2 = (T)((object)t);
						flag = this._handler(t2) > false;
					}
					endfilter(flag);
				})
				{
					disposable = Disposable.Empty;
				}
				return disposable;
			};
		}

		public CatchScheduler(IScheduler scheduler, Func<T, bool> handler, ConditionalWeakTable<IScheduler, IScheduler> cache)
			: base(scheduler, cache)
		{
			this._handler = handler;
		}

		protected override SchedulerWrapper Clone(IScheduler scheduler, ConditionalWeakTable<IScheduler, IScheduler> cache)
		{
			return new CatchScheduler<T>(scheduler, this._handler, cache);
		}

		protected override bool TryGetService(IServiceProvider provider, Type serviceType, out object service)
		{
			service = provider.GetService(serviceType);
			if (service != null)
			{
				if (serviceType == typeof(ISchedulerLongRunning))
				{
					service = new CatchScheduler<T>.CatchSchedulerLongRunning((ISchedulerLongRunning)service, this._handler);
				}
				else if (serviceType == typeof(GInterface7))
				{
					service = new CatchScheduler<T>.CatchSchedulerPeriodic((GInterface7)service, this._handler);
				}
			}
			return true;
		}

		private readonly Func<T, bool> _handler;

		private class CatchSchedulerLongRunning : ISchedulerLongRunning
		{
			public CatchSchedulerLongRunning(ISchedulerLongRunning scheduler, Func<T, bool> handler)
			{
				this._scheduler = scheduler;
				this._handler = handler;
			}

			public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)
			{
				return this._scheduler.ScheduleLongRunning<ValueTuple<CatchScheduler<T>.CatchSchedulerLongRunning, Action<TState, ICancelable>, TState>>(new ValueTuple<CatchScheduler<T>.CatchSchedulerLongRunning, Action<TState, ICancelable>, TState>(this, action, state), delegate([TupleElementNames(new string[] { "scheduler", "action", "state" })] ValueTuple<CatchScheduler<T>.CatchSchedulerLongRunning, Action<TState, ICancelable>, TState> tuple, ICancelable cancel)
				{
					object obj;
					T t;
					bool flag;
					T t2;
					try
					{
						tuple.Item2(tuple.Item3, cancel);
					}
					catch when (delegate
					{
						// Failed to create a 'catch-when' expression
						t = obj as T;
						if (t == null)
						{
							flag = false;
						}
						else
						{
							t2 = (T)((object)t);
							flag = tuple.Item1._handler(t2) > false;
						}
						endfilter(flag);
					})
					{
					}
				});
			}

			private readonly ISchedulerLongRunning _scheduler;

			private readonly Func<T, bool> _handler;
		}

		private sealed class CatchSchedulerPeriodic : GInterface7
		{
			public CatchSchedulerPeriodic(GInterface7 scheduler, Func<T, bool> handler)
			{
				this._scheduler = scheduler;
				this._handler = handler;
			}

			public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
			{
				return new CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>(this, state, period, action);
			}

			private readonly GInterface7 _scheduler;

			private readonly Func<T, bool> _handler;

			private sealed class PeriodicallyScheduledWorkItem<TState> : IDisposable
			{
				public PeriodicallyScheduledWorkItem(CatchScheduler<T>.CatchSchedulerPeriodic scheduler, TState state, TimeSpan period, Func<TState, TState> action)
				{
					this._catchScheduler = scheduler;
					this._action = action;
					Disposable.SetSingle(ref this._cancel, scheduler._scheduler.SchedulePeriodic<ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>>(new ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>(this, state), period, delegate([TupleElementNames(new string[] { "this", "state" })] ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState> tuple)
					{
						CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState> item = tuple.Item1;
						if (item == null)
						{
							return default(ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>);
						}
						return item.Tick(tuple.Item2);
					}));
				}

				public void Dispose()
				{
					Disposable.TryDispose(ref this._cancel);
				}

				[return: TupleElementNames(new string[] { "this", "state" })]
				private ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState> Tick(TState state)
				{
					ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState> valueTuple;
					if (this._failed)
					{
						valueTuple = default(ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>);
						return valueTuple;
					}
					try
					{
						valueTuple = new ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>(this, this._action(state));
					}
					catch (T t)
					{
						T t2 = (T)((object)t);
						this._failed = true;
						if (!this._catchScheduler._handler(t2))
						{
							throw;
						}
						Disposable.TryDispose(ref this._cancel);
						valueTuple = default(ValueTuple<CatchScheduler<T>.CatchSchedulerPeriodic.PeriodicallyScheduledWorkItem<TState>, TState>);
					}
					return valueTuple;
				}

				private IDisposable _cancel;

				private bool _failed;

				private readonly Func<TState, TState> _action;

				private readonly CatchScheduler<T>.CatchSchedulerPeriodic _catchScheduler;
			}
		}
	}
}
