using System;
using System.Globalization;
using System.Reactive.Disposables;
using System.Reactive.PlatformServices;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Concurrency
{
	public static class Scheduler
	{
		public static SchedulerOperation Yield(this IScheduler scheduler)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(a), scheduler.GetCancellationToken());
		}

		public static SchedulerOperation Yield(this IScheduler scheduler, CancellationToken cancellationToken)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(a), cancellationToken);
		}

		public static SchedulerOperation Sleep(this IScheduler scheduler, TimeSpan dueTime)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(dueTime, a), scheduler.GetCancellationToken());
		}

		public static SchedulerOperation Sleep(this IScheduler scheduler, TimeSpan dueTime, CancellationToken cancellationToken)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(dueTime, a), cancellationToken);
		}

		public static SchedulerOperation Sleep(this IScheduler scheduler, DateTimeOffset dueTime)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(dueTime, a), scheduler.GetCancellationToken());
		}

		public static SchedulerOperation Sleep(this IScheduler scheduler, DateTimeOffset dueTime, CancellationToken cancellationToken)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new SchedulerOperation((Action a) => scheduler.Schedule(dueTime, a), cancellationToken);
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, action);
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, action);
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, Func<IScheduler, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task>>(scheduler, action, (IScheduler self, Func<IScheduler, CancellationToken, Task> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task<IDisposable>>>(scheduler, action, (IScheduler self, Func<IScheduler, CancellationToken, Task<IDisposable>> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, dueTime, action);
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, dueTime, action);
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, TimeSpan dueTime, Func<IScheduler, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task>>(scheduler, action, dueTime, (IScheduler self, Func<IScheduler, CancellationToken, Task> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, TimeSpan dueTime, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task<IDisposable>>>(scheduler, action, dueTime, (IScheduler self, Func<IScheduler, CancellationToken, Task<IDisposable>> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, dueTime, action);
		}

		public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<TState>(scheduler, state, dueTime, action);
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, DateTimeOffset dueTime, Func<IScheduler, CancellationToken, Task> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task>>(scheduler, action, dueTime, (IScheduler self, Func<IScheduler, CancellationToken, Task> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		public static IDisposable ScheduleAsync(this IScheduler scheduler, DateTimeOffset dueTime, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.ScheduleAsync_<Func<IScheduler, CancellationToken, Task<IDisposable>>>(scheduler, action, dueTime, (IScheduler self, Func<IScheduler, CancellationToken, Task<IDisposable>> closureAction, CancellationToken ct) => closureAction(self, ct));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>(state, action), (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>(state, action), (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>(state, action), dueTime, (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>(state, action), dueTime, (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>>(state, action), dueTime, (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable ScheduleAsync_<TState>(object scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			return ((IScheduler)scheduler).Schedule<ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>>(new ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>>(state, action), dueTime, (IScheduler self, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<IScheduler, TState, CancellationToken, Task<IDisposable>>> t) => Scheduler.InvokeAsync<TState>(self, t.Item1, t.Item2));
		}

		private static IDisposable InvokeAsync<TState>(object self, TState s, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
		{
			return new Scheduler.AsyncInvocation<TState>().Run(self, s, action);
		}

		private static IDisposable InvokeAsync<TState>(object self, TState s, Func<IScheduler, TState, CancellationToken, Task> action)
		{
			return Scheduler.InvokeAsync<ValueTuple<Func<IScheduler, TState, CancellationToken, Task>, TState>>(self, new ValueTuple<Func<IScheduler, TState, CancellationToken, Task>, TState>(action, s), (IScheduler self_, [TupleElementNames(new string[] { "action", "state" })] ValueTuple<Func<IScheduler, TState, CancellationToken, Task>, TState> t, CancellationToken ct) => t.Item1(self_, t.Item2, ct).ContinueWith<IDisposable>((Task _) => Disposable.Empty));
		}

		private static CancellationToken GetCancellationToken(this object scheduler)
		{
			Scheduler.CancelableScheduler cancelableScheduler = scheduler as Scheduler.CancelableScheduler;
			if (cancelableScheduler == null)
			{
				return CancellationToken.None;
			}
			return cancelableScheduler.Token;
		}

		public static DateTimeOffset Now
		{
			get
			{
				return SystemClock.UtcNow;
			}
		}

		public static TimeSpan Normalize(TimeSpan timeSpan)
		{
			if (timeSpan.Ticks >= 0L)
			{
				return timeSpan;
			}
			return TimeSpan.Zero;
		}

		public static ImmediateScheduler Immediate
		{
			get
			{
				return ImmediateScheduler.Instance;
			}
		}

		public static CurrentThreadScheduler CurrentThread
		{
			get
			{
				return CurrentThreadScheduler.Instance;
			}
		}

		public static DefaultScheduler Default
		{
			get
			{
				return DefaultScheduler.Instance;
			}
		}

		[Obsolete("This property is no longer supported due to refactoring of the API surface and elimination of platform-specific dependencies. Consider using Scheduler.Default to obtain the platform's most appropriate pool-based scheduler. In order to access a specific pool-based scheduler, please add a reference to the System.Reactive.PlatformServices assembly for your target platform and use the appropriate scheduler in the System.Reactive.Concurrency namespace.")]
		public static IScheduler ThreadPool
		{
			get
			{
				return Scheduler._threadPool.Value;
			}
		}

		[Obsolete("This property is no longer supported due to refactoring of the API surface and elimination of platform-specific dependencies. Please use NewThreadScheduler.Default to obtain an instance of this scheduler type.")]
		public static IScheduler NewThread
		{
			get
			{
				return Scheduler._newThread.Value;
			}
		}

		[Obsolete("This property is no longer supported due to refactoring of the API surface and elimination of platform-specific dependencies. Please use TaskPoolScheduler.Default to obtain an instance of this scheduler type.")]
		public static IScheduler TaskPool
		{
			get
			{
				return Scheduler._taskPool.Value;
			}
		}

		private static IScheduler Initialize(object name)
		{
			IScheduler service = PlatformEnlightenmentProvider.Current.GetService<IScheduler>(new object[] { name });
			if (service == null)
			{
				throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings_Core.CANT_OBTAIN_SCHEDULER, name));
			}
			return service;
		}

		public static IDisposable Schedule(this IScheduler scheduler, Action<Action> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule(action, delegate(Action<Action> _action, Action<Action<Action>> self)
			{
				_action(delegate
				{
					self(_action);
				});
			});
		}

		public static IDisposable Schedule<TState>(this IScheduler scheduler, TState state, Action<TState, Action<TState>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Action<TState, Action<TState>>>>(new ValueTuple<TState, Action<TState, Action<TState>>>(state, action), (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState>>> p) => Scheduler.InvokeRec1<TState>(s, p));
		}

		private static IDisposable InvokeRec1<TState>(object scheduler, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState>>> tuple)
		{
			Scheduler.InvokeRec1State<TState> invokeRec1State = new Scheduler.InvokeRec1State<TState>(scheduler, tuple.Item2);
			invokeRec1State.InvokeFirst(tuple.Item1);
			return invokeRec1State;
		}

		public static IDisposable Schedule(this IScheduler scheduler, TimeSpan dueTime, Action<Action<TimeSpan>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule(action, dueTime, delegate(Action<Action<TimeSpan>> _action, Action<Action<Action<TimeSpan>>, TimeSpan> self)
			{
				_action(delegate(TimeSpan dt)
				{
					self(_action, dt);
				});
			});
		}

		public static IDisposable Schedule<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Action<TState, Action<TState, TimeSpan>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Action<TState, Action<TState, TimeSpan>>>>(new ValueTuple<TState, Action<TState, Action<TState, TimeSpan>>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState, TimeSpan>>> p) => Scheduler.InvokeRec2<TState>(s, p));
		}

		private static IDisposable InvokeRec2<TState>(object scheduler, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState, TimeSpan>>> tuple)
		{
			Scheduler.InvokeRec2State<TState> invokeRec2State = new Scheduler.InvokeRec2State<TState>(scheduler, tuple.Item2);
			invokeRec2State.InvokeFirst(tuple.Item1);
			return invokeRec2State;
		}

		public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action<Action<DateTimeOffset>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule(action, dueTime, delegate(Action<Action<DateTimeOffset>> _action, Action<Action<Action<DateTimeOffset>>, DateTimeOffset> self)
			{
				_action(delegate(DateTimeOffset dt)
				{
					self(_action, dt);
				});
			});
		}

		public static IDisposable Schedule<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Action<TState, Action<TState, DateTimeOffset>> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Action<TState, Action<TState, DateTimeOffset>>>>(new ValueTuple<TState, Action<TState, Action<TState, DateTimeOffset>>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState, DateTimeOffset>>> p) => Scheduler.InvokeRec3<TState>(s, p));
		}

		private static IDisposable InvokeRec3<TState>(object scheduler, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState, Action<TState, DateTimeOffset>>> tuple)
		{
			Scheduler.InvokeRec3State<TState> invokeRec3State = new Scheduler.InvokeRec3State<TState>(scheduler, tuple.Item2);
			invokeRec3State.InvokeFirst(tuple.Item1);
			return invokeRec3State;
		}

		public static ISchedulerLongRunning AsLongRunning(this IScheduler scheduler)
		{
			return Scheduler.As<ISchedulerLongRunning>(scheduler);
		}

		private static T As<T>(object scheduler) where T : class
		{
			IServiceProvider serviceProvider = scheduler as IServiceProvider;
			if (serviceProvider != null)
			{
				return (T)((object)serviceProvider.GetService(typeof(T)));
			}
			return default(T);
		}

		public static IDisposable SchedulePeriodic<TState>(this IScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (period < TimeSpan.Zero)
			{
				throw new ArgumentOutOfRangeException("period");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.SchedulePeriodic_<TState>(scheduler, state, period, action);
		}

		public static IDisposable SchedulePeriodic<TState>(this IScheduler scheduler, TState state, TimeSpan period, Action<TState> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (period < TimeSpan.Zero)
			{
				throw new ArgumentOutOfRangeException("period");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.SchedulePeriodic_<ValueTuple<TState, Action<TState>>>(scheduler, new ValueTuple<TState, Action<TState>>(state, action), period, delegate([TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState>> t)
			{
				t.Item2(t.Item1);
				return t;
			});
		}

		public static IDisposable SchedulePeriodic(this IScheduler scheduler, TimeSpan period, Action action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (period < TimeSpan.Zero)
			{
				throw new ArgumentOutOfRangeException("period");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return Scheduler.SchedulePeriodic_<Action>(scheduler, action, period, delegate(Action a)
			{
				a();
				return a;
			});
		}

		public static IStopwatch StartStopwatch(this IScheduler scheduler)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			GInterface8 ginterface = Scheduler.As<GInterface8>(scheduler);
			if (ginterface != null)
			{
				return ginterface.StartStopwatch();
			}
			return new Scheduler.EmulatedStopwatch(scheduler);
		}

		private static IDisposable SchedulePeriodic_<TState>(object scheduler, TState state, TimeSpan period, Func<TState, TState> action)
		{
			GInterface7 ginterface = Scheduler.As<GInterface7>(scheduler);
			if (ginterface != null)
			{
				return ginterface.SchedulePeriodic<TState>(state, period, action);
			}
			GInterface8 ginterface2 = Scheduler.As<GInterface8>(scheduler);
			if (ginterface2 != null)
			{
				return new Scheduler.SchedulePeriodicStopwatch<TState>(scheduler, state, period, action, ginterface2).Start();
			}
			return new Scheduler.SchedulePeriodicRecursive<TState>(scheduler, state, period, action).Start();
		}

		public static IDisposable Schedule(this IScheduler scheduler, Action action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<Action>(action, (IScheduler s, Action a) => Scheduler.Invoke(s, a));
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, Action<TState> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<Action<TState>, TState>>(new ValueTuple<Action<TState>, TState>(action, state), delegate(IScheduler _, [TupleElementNames(new string[] { "action", "state" })] ValueTuple<Action<TState>, TState> tuple)
			{
				tuple.Item1(tuple.Item2);
				return Disposable.Empty;
			});
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, Func<TState, IDisposable> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<Func<TState, IDisposable>, TState>>(new ValueTuple<Func<TState, IDisposable>, TState>(action, state), (IScheduler _, [TupleElementNames(new string[] { "action", "state" })] ValueTuple<Func<TState, IDisposable>, TState> tuple) => tuple.Item1(tuple.Item2));
		}

		public static IDisposable Schedule(this IScheduler scheduler, TimeSpan dueTime, Action action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<Action>(action, dueTime, (IScheduler s, Action a) => Scheduler.Invoke(s, a));
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Action<TState> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Action<TState>>>(new ValueTuple<TState, Action<TState>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState>> tuple) => Scheduler.Invoke<TState>(s, tuple));
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Func<TState, IDisposable> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Func<TState, IDisposable>>>(new ValueTuple<TState, Func<TState, IDisposable>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<TState, IDisposable>> tuple) => Scheduler.Invoke<TState>(s, tuple));
		}

		public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<Action>(action, dueTime, (IScheduler s, Action a) => Scheduler.Invoke(s, a));
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Action<TState> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Action<TState>>>(new ValueTuple<TState, Action<TState>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState>> tuple) => Scheduler.Invoke<TState>(s, tuple));
		}

		internal static IDisposable ScheduleAction<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<TState, IDisposable> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.Schedule<ValueTuple<TState, Func<TState, IDisposable>>>(new ValueTuple<TState, Func<TState, IDisposable>>(state, action), dueTime, (IScheduler s, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<TState, IDisposable>> tuple) => Scheduler.Invoke<TState>(s, tuple));
		}

		public static IDisposable ScheduleLongRunning(this ISchedulerLongRunning scheduler, Action<ICancelable> action)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			return scheduler.ScheduleLongRunning<Action<ICancelable>>(action, delegate(Action<ICancelable> a, ICancelable c)
			{
				a(c);
			});
		}

		private static IDisposable Invoke(IScheduler scheduler, Action action)
		{
			action();
			return Disposable.Empty;
		}

		private static IDisposable Invoke<TState>(IScheduler scheduler, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Action<TState>> tuple)
		{
			tuple.Item2(tuple.Item1);
			return Disposable.Empty;
		}

		private static IDisposable Invoke<TState>(IScheduler scheduler, [TupleElementNames(new string[] { "state", "action" })] ValueTuple<TState, Func<TState, IDisposable>> tuple)
		{
			return tuple.Item2(tuple.Item1);
		}

		public static IScheduler DisableOptimizations(this IScheduler scheduler)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return new DisableOptimizationsScheduler(scheduler);
		}

		public static IScheduler DisableOptimizations(this IScheduler scheduler, params Type[] optimizationInterfaces)
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (optimizationInterfaces == null)
			{
				throw new ArgumentNullException("optimizationInterfaces");
			}
			return new DisableOptimizationsScheduler(scheduler, optimizationInterfaces);
		}

		public static IScheduler Catch<T>(this IScheduler scheduler, Func<T, bool> handler) where T : Exception
		{
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			return new CatchScheduler<T>(scheduler, handler);
		}

		private static readonly Lazy<IScheduler> _threadPool = new Lazy<IScheduler>(() => Scheduler.Initialize("ThreadPool"));

		private static readonly Lazy<IScheduler> _newThread = new Lazy<IScheduler>(() => Scheduler.Initialize("NewThread"));

		private static readonly Lazy<IScheduler> _taskPool = new Lazy<IScheduler>(() => Scheduler.Initialize("TaskPool"));

		internal static Type[] Optimizations = new Type[]
		{
			typeof(ISchedulerLongRunning),
			typeof(GInterface8),
			typeof(GInterface7)
		};

		private sealed class AsyncInvocation<TState> : IDisposable
		{
			public IDisposable Run(IScheduler self, TState s, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
			{
				if (this._cts.IsCancellationRequested)
				{
					return Disposable.Empty;
				}
				action(new Scheduler.CancelableScheduler(self, this._cts.Token), s, this._cts.Token).ContinueWith(delegate(Task<IDisposable> t, object thisObject)
				{
					Scheduler.AsyncInvocation<TState> asyncInvocation = (Scheduler.AsyncInvocation<TState>)thisObject;
					AggregateException exception = t.Exception;
					if (exception != null)
					{
						exception.Handle((Exception e) => e is OperationCanceledException);
					}
					Disposable.SetSingle(ref asyncInvocation._run, t.Result);
				}, this, TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.ExecuteSynchronously);
				return this;
			}

			public void Dispose()
			{
				this._cts.Cancel();
				Disposable.TryDispose(ref this._run);
			}

			private readonly CancellationTokenSource _cts = new CancellationTokenSource();

			private IDisposable _run;
		}

		private sealed class CancelableScheduler : IScheduler
		{
			public CancelableScheduler(IScheduler scheduler, CancellationToken cancellationToken)
			{
				this._scheduler = scheduler;
				this._cancellationToken = cancellationToken;
			}

			public CancellationToken Token
			{
				get
				{
					return this._cancellationToken;
				}
			}

			public DateTimeOffset Now
			{
				get
				{
					return ((IScheduler)this._scheduler).Now;
				}
			}

			public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
			{
				return ((IScheduler)this._scheduler).Schedule<TState>(state, action);
			}

			public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
			{
				return ((IScheduler)this._scheduler).Schedule<TState>(state, dueTime, action);
			}

			public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
			{
				return ((IScheduler)this._scheduler).Schedule<TState>(state, dueTime, action);
			}

			private readonly object _scheduler;

			private readonly CancellationToken _cancellationToken;
		}

		private abstract class InvokeRecBaseState : IDisposable
		{
			protected InvokeRecBaseState(IScheduler scheduler)
			{
				this.Scheduler = scheduler;
				this.Group = new CompositeDisposable();
			}

			public void Dispose()
			{
				this.Group.Dispose();
			}

			protected readonly object Scheduler;

			protected readonly object Group;
		}

		private sealed class InvokeRec1State<TState> : Scheduler.InvokeRecBaseState
		{
			public InvokeRec1State(IScheduler scheduler, Action<TState, Action<TState>> action)
				: base(scheduler)
			{
				this._action = action;
				this._recurseCallback = delegate(TState state)
				{
					this.InvokeNext(state);
				};
			}

			private void InvokeNext(TState state)
			{
				SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
				this.Group.Add(singleAssignmentDisposable);
				singleAssignmentDisposable.Disposable = this.Scheduler.ScheduleAction(new ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec1State<TState>>(state, singleAssignmentDisposable, this), delegate([TupleElementNames(new string[] { "state", "sad", "this" })] ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec1State<TState>> nextState)
				{
					nextState.Item3.Group.Remove(nextState.Item2);
					nextState.Item3.InvokeFirst(nextState.Item1);
				});
			}

			internal void InvokeFirst(TState state)
			{
				this._action(state, this._recurseCallback);
			}

			private readonly Action<TState, Action<TState>> _action;

			private readonly Action<TState> _recurseCallback;
		}

		private sealed class InvokeRec2State<TState> : Scheduler.InvokeRecBaseState
		{
			public InvokeRec2State(IScheduler scheduler, Action<TState, Action<TState, TimeSpan>> action)
				: base(scheduler)
			{
				this._action = action;
				this._recurseCallback = delegate(TState state, TimeSpan time)
				{
					this.InvokeNext(state, time);
				};
			}

			private void InvokeNext(TState state, TimeSpan time)
			{
				SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
				this.Group.Add(singleAssignmentDisposable);
				singleAssignmentDisposable.Disposable = this.Scheduler.ScheduleAction(new ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec2State<TState>>(state, singleAssignmentDisposable, this), time, delegate([TupleElementNames(new string[] { "state", "sad", "this" })] ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec2State<TState>> nextState)
				{
					nextState.Item3.Group.Remove(nextState.Item2);
					nextState.Item3.InvokeFirst(nextState.Item1);
				});
			}

			internal void InvokeFirst(TState state)
			{
				this._action(state, this._recurseCallback);
			}

			private readonly Action<TState, Action<TState, TimeSpan>> _action;

			private readonly Action<TState, TimeSpan> _recurseCallback;
		}

		private sealed class InvokeRec3State<TState> : Scheduler.InvokeRecBaseState
		{
			public InvokeRec3State(IScheduler scheduler, Action<TState, Action<TState, DateTimeOffset>> action)
				: base(scheduler)
			{
				this._action = action;
				this._recurseCallback = delegate(TState state, DateTimeOffset dtOffset)
				{
					this.InvokeNext(state, dtOffset);
				};
			}

			private void InvokeNext(TState state, DateTimeOffset dtOffset)
			{
				SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
				this.Group.Add(singleAssignmentDisposable);
				singleAssignmentDisposable.Disposable = this.Scheduler.ScheduleAction(new ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec3State<TState>>(state, singleAssignmentDisposable, this), dtOffset, delegate([TupleElementNames(new string[] { "state", "sad", "this" })] ValueTuple<TState, SingleAssignmentDisposable, Scheduler.InvokeRec3State<TState>> nextState)
				{
					nextState.Item3.Group.Remove(nextState.Item2);
					nextState.Item3.InvokeFirst(nextState.Item1);
				});
			}

			internal void InvokeFirst(TState state)
			{
				this._action(state, this._recurseCallback);
			}

			private readonly Action<TState, Action<TState, DateTimeOffset>> _action;

			private readonly Action<TState, DateTimeOffset> _recurseCallback;
		}

		private sealed class SchedulePeriodicStopwatch<TState> : IDisposable
		{
			public SchedulePeriodicStopwatch(IScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action, GInterface8 stopwatchProvider)
			{
				this._scheduler = scheduler;
				this._period = period;
				this._action = action;
				this._stopwatchProvider = stopwatchProvider;
				this._state = state;
				this._runState = 0;
			}

			public IDisposable Start()
			{
				this.RegisterHostLifecycleEventHandlers();
				this._stopwatch = this._stopwatchProvider.StartStopwatch();
				this._nextDue = this._period;
				this._runState = 1;
				Disposable.TrySetSingle(ref this._task, this._scheduler.Schedule(this, this._nextDue, delegate(Scheduler.SchedulePeriodicStopwatch<TState> @this, Action<Scheduler.SchedulePeriodicStopwatch<TState>, TimeSpan> a)
				{
					@this.Tick(a);
				}));
				return this;
			}

			void IDisposable.Dispose()
			{
				Disposable.TryDispose(ref this._task);
				this.Cancel();
			}

			private void Tick(Action<Scheduler.SchedulePeriodicStopwatch<TState>, TimeSpan> recurse)
			{
				this._nextDue += this._period;
				this._state = this._action(this._state);
				TimeSpan timeSpan = default(TimeSpan);
				for (;;)
				{
					object gate = this._gate;
					lock (gate)
					{
						if (this._runState == 1)
						{
							timeSpan = Scheduler.Normalize(this._nextDue - (this._stopwatch.Elapsed - this._inactiveTime));
							break;
						}
						if (this._runState == 3)
						{
							return;
						}
					}
					this._resumeEvent.WaitOne();
				}
				recurse(this, timeSpan);
			}

			private void Cancel()
			{
				this.UnregisterHostLifecycleEventHandlers();
				object gate = this._gate;
				lock (gate)
				{
					this._runState = 3;
					if (!Environment.HasShutdownStarted)
					{
						this._resumeEvent.Set();
					}
				}
			}

			private void Suspending(object sender, HostSuspendingEventArgs e)
			{
				object gate = this._gate;
				lock (gate)
				{
					if (this._runState == 1)
					{
						this._suspendedAt = this._stopwatch.Elapsed;
						this._runState = 2;
						if (!Environment.HasShutdownStarted)
						{
							this._resumeEvent.Reset();
						}
					}
				}
			}

			private void Resuming(object sender, HostResumingEventArgs e)
			{
				object gate = this._gate;
				lock (gate)
				{
					if (this._runState == 2)
					{
						this._inactiveTime += this._stopwatch.Elapsed - this._suspendedAt;
						this._runState = 1;
						if (!Environment.HasShutdownStarted)
						{
							this._resumeEvent.Set();
						}
					}
				}
			}

			private void RegisterHostLifecycleEventHandlers()
			{
				HostLifecycleService.Suspending += this.Suspending;
				HostLifecycleService.Resuming += this.Resuming;
				HostLifecycleService.AddRef();
			}

			private void UnregisterHostLifecycleEventHandlers()
			{
				HostLifecycleService.Suspending -= this.Suspending;
				HostLifecycleService.Resuming -= this.Resuming;
				HostLifecycleService.Release();
			}

			private readonly IScheduler _scheduler;

			private readonly TimeSpan _period;

			private readonly Func<TState, TState> _action;

			private readonly GInterface8 _stopwatchProvider;

			private TState _state;

			private readonly object _gate = new object();

			private readonly AutoResetEvent _resumeEvent = new AutoResetEvent(false);

			private volatile int _runState;

			private IStopwatch _stopwatch;

			private TimeSpan _nextDue;

			private TimeSpan _suspendedAt;

			private TimeSpan _inactiveTime;

			private IDisposable _task;
		}

		private sealed class SchedulePeriodicRecursive<TState>
		{
			public SchedulePeriodicRecursive(IScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action)
			{
				this._scheduler = scheduler;
				this._period = period;
				this._action = action;
				this._state = state;
			}

			public IDisposable Start()
			{
				this._pendingTickCount = 0;
				SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
				this._cancel = singleAssignmentDisposable;
				singleAssignmentDisposable.Disposable = this._scheduler.Schedule(0, this._period, new Action<int, Action<int, TimeSpan>>(this.Tick));
				return singleAssignmentDisposable;
			}

			private void Tick(int command, Action<int, TimeSpan> recurse)
			{
				switch (command)
				{
				case 0:
					recurse(0, this._period);
					if (Interlocked.Increment(ref this._pendingTickCount) != 1)
					{
						return;
					}
					break;
				case 1:
					break;
				case 2:
					if (Interlocked.Decrement(ref this._pendingTickCount) > 0)
					{
						recurse(1, TimeSpan.Zero);
						return;
					}
					return;
				default:
					return;
				}
				try
				{
					this._state = this._action(this._state);
				}
				catch (Exception ex)
				{
					this._cancel.Dispose();
					ex.Throw();
				}
				recurse(2, TimeSpan.Zero);
			}

			private readonly IScheduler _scheduler;

			private readonly TimeSpan _period;

			private readonly Func<TState, TState> _action;

			private TState _state;

			private int _pendingTickCount;

			private IDisposable _cancel;
		}

		private sealed class EmulatedStopwatch : IStopwatch
		{
			public EmulatedStopwatch(IScheduler scheduler)
			{
				this._scheduler = scheduler;
				this._start = ((IScheduler)this._scheduler).Now;
			}

			public TimeSpan Elapsed
			{
				get
				{
					return Scheduler.Normalize(((IScheduler)this._scheduler).Now - this._start);
				}
			}

			private readonly object _scheduler;

			private readonly DateTimeOffset _start;
		}
	}
}
