using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Concurrency;
using System.Threading;

namespace System.Reactive.PlatformServices
{
	[EditorBrowsable(EditorBrowsableState.Never)]
	public static class SystemClock
	{
		public static DateTimeOffset UtcNow
		{
			get
			{
				return SystemClock.ServiceSystemClock.Value.UtcNow;
			}
		}

		public static void AddRef()
		{
			if (Interlocked.Increment(ref SystemClock._refCount) == 1)
			{
				SystemClock.ServiceSystemClockChanged.Value.SystemClockChanged += SystemClock.OnSystemClockChanged;
			}
		}

		public static void Release()
		{
			if (Interlocked.Decrement(ref SystemClock._refCount) == 0)
			{
				SystemClock.ServiceSystemClockChanged.Value.SystemClockChanged -= SystemClock.OnSystemClockChanged;
			}
		}

		internal static void OnSystemClockChanged(object sender, SystemClockChangedEventArgs e)
		{
			HashSet<WeakReference<LocalScheduler>> systemClockChanged = SystemClock.SystemClockChanged;
			lock (systemClockChanged)
			{
				using (List<WeakReference<LocalScheduler>>.Enumerator enumerator = new List<WeakReference<LocalScheduler>>(SystemClock.SystemClockChanged).GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						LocalScheduler localScheduler;
						if (enumerator.Current.TryGetTarget(out localScheduler))
						{
							localScheduler.SystemClockChanged(sender, e);
						}
					}
				}
			}
		}

		private static ISystemClock InitializeSystemClock()
		{
			return PlatformEnlightenmentProvider.Current.GetService<ISystemClock>(Array.Empty<object>()) ?? new DefaultSystemClock();
		}

		private static INotifySystemClockChanged InitializeSystemClockChanged()
		{
			return PlatformEnlightenmentProvider.Current.GetService<INotifySystemClockChanged>(Array.Empty<object>()) ?? new DefaultSystemClockMonitor();
		}

		internal static void Register(LocalScheduler scheduler)
		{
			HashSet<WeakReference<LocalScheduler>> systemClockChanged = SystemClock.SystemClockChanged;
			lock (systemClockChanged)
			{
				SystemClock.SystemClockChanged.Add(new WeakReference<LocalScheduler>(scheduler));
				if (SystemClock.SystemClockChanged.Count == 1)
				{
					SystemClock._systemClockChangedHandlerCollector = ConcurrencyAbstractionLayer.Current.StartPeriodicTimer(new Action(SystemClock.CollectHandlers), TimeSpan.FromSeconds(30.0));
				}
				else if (SystemClock.SystemClockChanged.Count % 64 == 0)
				{
					SystemClock.CollectHandlers();
				}
			}
		}

		private static void CollectHandlers()
		{
			HashSet<WeakReference<LocalScheduler>> systemClockChanged = SystemClock.SystemClockChanged;
			lock (systemClockChanged)
			{
				HashSet<WeakReference<LocalScheduler>> hashSet = null;
				foreach (WeakReference<LocalScheduler> weakReference in SystemClock.SystemClockChanged)
				{
					LocalScheduler localScheduler;
					if (!weakReference.TryGetTarget(out localScheduler))
					{
						if (hashSet == null)
						{
							hashSet = new HashSet<WeakReference<LocalScheduler>>();
						}
						hashSet.Add(weakReference);
					}
				}
				if (hashSet != null)
				{
					foreach (WeakReference<LocalScheduler> weakReference2 in hashSet)
					{
						SystemClock.SystemClockChanged.Remove(weakReference2);
					}
				}
				if (SystemClock.SystemClockChanged.Count == 0)
				{
					SystemClock._systemClockChangedHandlerCollector.Dispose();
					SystemClock._systemClockChangedHandlerCollector = null;
				}
			}
		}

		private static readonly Lazy<ISystemClock> ServiceSystemClock = new Lazy<ISystemClock>(new Func<ISystemClock>(SystemClock.InitializeSystemClock));

		private static readonly Lazy<INotifySystemClockChanged> ServiceSystemClockChanged = new Lazy<INotifySystemClockChanged>(new Func<INotifySystemClockChanged>(SystemClock.InitializeSystemClockChanged));

		internal static readonly HashSet<WeakReference<LocalScheduler>> SystemClockChanged = new HashSet<WeakReference<LocalScheduler>>();

		private static IDisposable _systemClockChangedHandlerCollector;

		private static int _refCount;
	}
}
