// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
using System.Threading;
namespace System.Reactive.PlatformServices
{
    /// 
    /// (Infrastructure) Provides access to local system clock services.
    /// 
    /// 
    /// This type is used by the Rx infrastructure and not meant for public consumption or implementation.
    /// No guarantees are made about forward compatibility of the type's functionality and its usage.
    /// 
    [EditorBrowsable(EditorBrowsableState.Never)]
    public static class SystemClock
    {
        private static Lazy s_serviceSystemClock = new Lazy(InitializeSystemClock);
        private static Lazy s_serviceSystemClockChanged = new Lazy(InitializeSystemClockChanged);
        private static int _refCount;
        /// 
        /// Gets the local system clock time.
        /// 
        public static DateTimeOffset UtcNow
        {
            get { return s_serviceSystemClock.Value.UtcNow; }
        }
        /// 
        /// Event that gets raised when a system clock change is detected, if there's any interest as indicated by AddRef calls.
        /// 
        public static event EventHandler SystemClockChanged;
        /// 
        /// Adds a reference to the system clock monitor, causing it to be sending notifications.
        /// 
        /// Thrown when the system doesn't support sending clock change notifications.
        public static void AddRef()
        {
            if (Interlocked.Increment(ref _refCount) == 1)
            {
                s_serviceSystemClockChanged.Value.SystemClockChanged += OnSystemClockChanged;
            }
        }
        /// 
        /// Removes a reference to the system clock monitor, causing it to stop sending notifications
        /// if the removed reference was the last one.
        /// 
        public static void Release()
        {
            if (Interlocked.Decrement(ref _refCount) == 0)
            {
                s_serviceSystemClockChanged.Value.SystemClockChanged -= OnSystemClockChanged;
            }
        }
        private static void OnSystemClockChanged(object sender, SystemClockChangedEventArgs e)
        {
            var scc = SystemClockChanged;
            if (scc != null)
                scc(sender, e);
        }
        private static ISystemClock InitializeSystemClock()
        {
            return PlatformEnlightenmentProvider.Current.GetService() ?? new DefaultSystemClock();
        }
        private static INotifySystemClockChanged InitializeSystemClockChanged()
        {
            return PlatformEnlightenmentProvider.Current.GetService() ?? new DefaultSystemClockMonitor();
        }
    }
    /// 
    /// (Infrastructure) Provides access to the local system clock.
    /// 
    /// 
    /// This type is used by the Rx infrastructure and not meant for public consumption or implementation.
    /// No guarantees are made about forward compatibility of the type's functionality and its usage.
    /// 
    [EditorBrowsable(EditorBrowsableState.Never)]
    public interface ISystemClock
    {
        /// 
        /// Gets the current time.
        /// 
        DateTimeOffset UtcNow { get; }
    }
    /// 
    /// (Infrastructure) Provides a mechanism to notify local schedulers about system clock changes.
    /// 
    /// 
    /// This type is used by the Rx infrastructure and not meant for public consumption or implementation.
    /// No guarantees are made about forward compatibility of the type's functionality and its usage.
    /// 
    [EditorBrowsable(EditorBrowsableState.Never)]
    public interface INotifySystemClockChanged
    {
        /// 
        /// Event that gets raised when a system clock change is detected.
        /// 
        event EventHandler SystemClockChanged;
    }
    /// 
    /// (Infrastructure) Event arguments for system clock change notifications.
    /// 
    /// 
    /// This type is used by the Rx infrastructure and not meant for public consumption or implementation.
    /// No guarantees are made about forward compatibility of the type's functionality and its usage.
    /// 
    [EditorBrowsable(EditorBrowsableState.Never)]
    public class SystemClockChangedEventArgs : EventArgs
    {
        /// 
        /// Creates a new system clock notification object with unknown old and new times.
        /// 
        public SystemClockChangedEventArgs()
            : this(DateTimeOffset.MinValue, DateTimeOffset.MaxValue)
        {
        }
        /// 
        /// Creates a new system clock notification object with the specified old and new times.
        /// 
        /// Time before the system clock changed, or DateTimeOffset.MinValue if not known.
        /// Time after the system clock changed, or DateTimeOffset.MaxValue if not known.
        public SystemClockChangedEventArgs(DateTimeOffset oldTime, DateTimeOffset newTime)
        {
            OldTime = oldTime;
            NewTime = newTime;
        }
        /// 
        /// Gets the time before the system clock changed, or DateTimeOffset.MinValue if not known.
        /// 
        public DateTimeOffset OldTime { get; private set; }
        /// 
        /// Gets the time after the system clock changed, or DateTimeOffset.MaxValue if not known.
        /// 
        public DateTimeOffset NewTime { get; private set; }
    }
}