using System;
using System.Reactive.Concurrency;
using System.Windows.Threading;

namespace System.Reactive.Linq
{
	public static class DispatcherObservable
	{
		public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, Dispatcher dispatcher)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, dispatcher);
		}

		public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, Dispatcher dispatcher, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, dispatcher, priority);
		}

		public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, DispatcherScheduler scheduler)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, scheduler.Dispatcher, scheduler.Priority);
		}

		public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, DispatcherObject dispatcherObject)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcherObject == null)
			{
				throw new ArgumentNullException("dispatcherObject");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, dispatcherObject.Dispatcher);
		}

		public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, DispatcherObject dispatcherObject, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcherObject == null)
			{
				throw new ArgumentNullException("dispatcherObject");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, dispatcherObject.Dispatcher, priority);
		}

		public static IObservable<TSource> ObserveOnDispatcher<TSource>(this IObservable<TSource> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, DispatcherScheduler.Current.Dispatcher);
		}

		public static IObservable<TSource> ObserveOnDispatcher<TSource>(this IObservable<TSource> source, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return DispatcherObservable.ObserveOn_<TSource>(source, DispatcherScheduler.Current.Dispatcher, priority);
		}

		private static IObservable<TSource> ObserveOn_<TSource>(IObservable<TSource> source, object dispatcher, DispatcherPriority priority)
		{
			return Synchronization.ObserveOn<TSource>(source, new DispatcherSynchronizationContext(dispatcher, priority));
		}

		private static IObservable<TSource> ObserveOn_<TSource>(IObservable<TSource> source, object dispatcher)
		{
			return Synchronization.ObserveOn<TSource>(source, new DispatcherSynchronizationContext(dispatcher));
		}

		public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, Dispatcher dispatcher)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, dispatcher);
		}

		public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, Dispatcher dispatcher, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcher == null)
			{
				throw new ArgumentNullException("dispatcher");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, dispatcher, priority);
		}

		public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, DispatcherScheduler scheduler)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (scheduler == null)
			{
				throw new ArgumentNullException("scheduler");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, scheduler.Dispatcher, scheduler.Priority);
		}

		public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, DispatcherObject dispatcherObject)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcherObject == null)
			{
				throw new ArgumentNullException("dispatcherObject");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, dispatcherObject.Dispatcher);
		}

		public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, DispatcherObject dispatcherObject, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (dispatcherObject == null)
			{
				throw new ArgumentNullException("dispatcherObject");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, dispatcherObject.Dispatcher, priority);
		}

		public static IObservable<TSource> SubscribeOnDispatcher<TSource>(this IObservable<TSource> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, DispatcherScheduler.Current.Dispatcher);
		}

		public static IObservable<TSource> SubscribeOnDispatcher<TSource>(this IObservable<TSource> source, DispatcherPriority priority)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return DispatcherObservable.SubscribeOn_<TSource>(source, DispatcherScheduler.Current.Dispatcher, priority);
		}

		private static IObservable<TSource> SubscribeOn_<TSource>(IObservable<TSource> source, object dispatcher, DispatcherPriority priority)
		{
			return Synchronization.SubscribeOn<TSource>(source, new DispatcherSynchronizationContext(dispatcher, priority));
		}

		private static IObservable<TSource> SubscribeOn_<TSource>(IObservable<TSource> source, object dispatcher)
		{
			return Synchronization.SubscribeOn<TSource>(source, new DispatcherSynchronizationContext(dispatcher));
		}
	}
}
