﻿// ###################### | #############################################################
// CLASS ................ | SOFTWARE DEVELOPMENT CAPSTONE (C868) ........................
// ASSIGNMENT ........... | C# PERFORMANCE ASSESSMENT ...................................
// TASK ................. | EZP1 TASK 2: SOFTWARE APPLICATION AND DOCUMENTATION .........
// ###################### | #############################################################
// WGU STUDENT .......... | Mark K Ewer .................................................
// STUDENT ID ........... | 001094518 ...................................................
// DEGREE PROGRAM ....... | B.S. in Software Development ................................
// ENROLLED ON .......... | Feb 1, 2019 .................................................
// MENTOR ............... | Becky Stovall ...............................................
// PHONE ................ | (904) 238-7347 ..............................................
// TIME ZONE ............ | Eastern Time ................................................
// EMAIL ................ | MEwer@wgu.edu or Mark@3w3r.com ..............................
// WEB SITE ............. | http://www.markewer.com .....................................
// ###################### | #############################################################
namespace Ewer.Cqrs.Views.ViewManagers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    /// <summary>
    ///   The wait handle is used to provide a uniform interface to the ability to wait in
    ///   a blocking fashion for one or more specific views to be updated. Construct the
    ///   handle and pass it into the configuration API when you configure your view
    ///   manager event dispatchers
    /// </summary>
    public class ViewManagerWaitHandle
    {
        private readonly List<IAwaitableEventDispatcher> _dispatchers = new List<IAwaitableEventDispatcher>();

        /// <summary>
        ///   Blocks until the view for the specified view model has processed the events
        ///   that were emitted in the unit of work that generated the given
        ///   <see cref="CommandProcessingResult" />. If that does not happen before
        ///   <seealso cref="timeout" /> has elapsed, a <see cref="TimeoutException" /> is
        ///   thrown.
        /// </summary>
        public async Task WaitFor<TViewInstance>(CommandProcessingResult result, TimeSpan timeout) where TViewInstance : IViewInstance
        {
            var tasks = _dispatchers
                .Select(d => d.WaitUntilProcessed<TViewInstance>(result, timeout))
                .ToArray();

            await Task.WhenAll(tasks);
        }

        /// <summary>
        ///   Blocks until all views have processed the events that were emitted in the
        ///   unit of work that generated the given
        ///   <see cref="CommandProcessingResult" />. If that does not happen before
        ///   <seealso cref="timeout" /> has elapsed, a <see cref="TimeoutException" /> is
        ///   thrown.
        /// </summary>
        public async Task WaitForAll(CommandProcessingResult result, TimeSpan timeout)
        {
            var tasks = _dispatchers
                .Select(d => d.WaitUntilProcessed(result, timeout))
                .ToArray();

            await Task.WhenAll(tasks);
        }

        internal void Register(IAwaitableEventDispatcher dispatcher)
        {
            _dispatchers.Add(dispatcher);
        }
    }
}
