namespace DesktopSprites.Core
{
    using System;

    /// <summary>
    /// Defines thread-safe Raise methods for <see cref="T:System.EventHandler"/> and <see cref="T:System.EventHandler`1"/>.
    /// </summary>
    public static class SafeEvent
    {
        /// <summary>
        /// Raises the event with no event data.
        /// </summary>
        /// <param name="eventHandler">The event to raise.</param>
        /// <param name="sender">The source of the event.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
            Justification = "This method provides event related functionality, but is not an event.")]
        public static void Raise(this EventHandler eventHandler, object sender)
        {
            EventHandler handler = eventHandler;
            if (handler != null)
                handler(sender, EventArgs.Empty);
        }

        /// <summary>
        /// Raises the event with specified event data.
        /// </summary>
        /// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
        /// <param name="eventHandler">The event to raise.</param>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The event data.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
            Justification = "This method provides event related functionality, but is not an event.")]
        public static void Raise<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e)
            where TEventArgs : EventArgs
        {
            EventHandler<TEventArgs> handler = eventHandler;
            if (handler != null)
                handler(sender, e);
        }

        /// <summary>
        /// Raises the event with lazily initialized event data.
        /// </summary>
        /// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
        /// <param name="eventHandler">The event to raise.</param>
        /// <param name="sender">The source of the event.</param>
        /// <param name="argsFactory">Function to generate event data if the event handler is not null.</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="argsFactory"/> is null.</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
            Justification = "This method provides event related functionality, but is not an event.")]
        public static void Raise<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, Func<TEventArgs> argsFactory)
            where TEventArgs : EventArgs
        {
            Argument.EnsureNotNull(argsFactory, "argsFactory");

            EventHandler<TEventArgs> handler = eventHandler;
            if (handler != null)
                handler(sender, argsFactory());
        }
    }
}
