/// <summary>
        /// Closes the next event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        internal void CloseNextEvent(object sender, AlarmEventArg e)
        {
            //un-box the sender
            EventGenerator currentGenerator = sender as EventGenerator;

            // find the next event to close
            int next = this._instanceGenerator.Next(_maxKey);

            while (!OpenAlarms.ContainsKey(next))
            {
                next = this._instanceGenerator.Next(_maxKey);
            }

            // remove from the collection of open events
            int value;

            OpenAlarms.TryRemove(next, out value);

            // queue the action
            currentGenerator?.OnActionQueued(new QueuedEventArg()
            {
                QueuedAction = () => { CloseAlarm(value, e.EventDateTime); }
            });

            //switch back to opening events
            this.OnSwitchingModes(EventArgs.Empty);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="EventService"/> class.
        /// </summary>
        /// <param name="frequency">The frequency in events per day</param>
        /// <param name="percentAlarm">The percentage of events to be alarms</param>
        internal EventService(int frequency, int percentAlarm)
        {
            var averageEventsPerSecond = (frequency / 86400.0) * 2;
            var averageDelayMs         = (1000.0 / averageEventsPerSecond);

            Console.Write("Frequency -> {0} Events per Second\n\r", averageEventsPerSecond.ToString(CultureInfo.CurrentCulture));
            Console.Write("Average Delay -> {0} ms\n\r", averageDelayMs.ToString(CultureInfo.CurrentCulture));

            this._eventService = new EventGenerator(averageDelayMs, percentAlarm);
            this._taskService  = new TaskProcessor(averageDelayMs);

            this._eventService.QueueActionForProcessing += this._taskService.QueueNextAction;
        }
        /// <summary>
        /// Opens the next event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        internal void OpenNextEvent(object sender, AlarmEventArg e)
        {
            // un-box the sender
            EventGenerator currentGenerator = sender as EventGenerator;

            // get the next threshold and type - don't open events already open
            int next = this._instanceGenerator.Next(TotalThresholds);

            while (OpenAlarms.ContainsKey(next))
            {
                next = this._instanceGenerator.Next(TotalThresholds);
            }
            if (e.EventType == EventGenerator.EventType.Alarm)
            {
                while (!this.IsAlarm(next))
                {
                    next = this._instanceGenerator.Next(TotalThresholds);
                }
            }
            else
            {
                while (!this.IsWarning(next))
                {
                    next = this._instanceGenerator.Next(TotalThresholds);
                }
            }

            // queue the action
            currentGenerator?.OnActionQueued(new QueuedEventArg()
            {
                QueuedAction = () => { OpenAlarm(next, e.EventDateTime); }
            });

            // toggle the mode - opening or closing if we have more than 25 open events
            if (OpenAlarms.Count > 25)
            {
                this.OnSwitchingModes(EventArgs.Empty);
            }
        }