internal bool CanProcessUpdate(TimeSpan updateFrequency, List <int> allowedUpdateUtcHours, UpdateEventInfo lastUpdateEventInfo)
        {
            var utcNow           = _dateTimeProxy.UtcNow;
            var currentTimeHours = utcNow.TimeOfDay.Hours;

            if (!allowedUpdateUtcHours.Contains(currentTimeHours))
            {
                return(false);
            }

            if (lastUpdateEventInfo != null)
            {
                var nextUpdateDate = lastUpdateEventInfo.StartedOn + updateFrequency;
                if (utcNow < nextUpdateDate)
                {
                    return(false);
                }

                if (lastUpdateEventInfo.UpdateResult == UpdateResult.NeedManualResolve)
                {
                    return(false);
                }
            }

            return(true);
        }
      internal bool CanProcessUpdate(TimeSpan updateFrequency, List<int> allowedUpdateUtcHours, UpdateEventInfo lastUpdateEventInfo)
      {
         var utcNow = _dateTimeProxy.UtcNow;
         var currentTimeHours = utcNow.TimeOfDay.Hours;

         if (!allowedUpdateUtcHours.Contains(currentTimeHours))
         {
            return false;
         }

         if (lastUpdateEventInfo != null)
         {
            var nextUpdateDate = lastUpdateEventInfo.StartedOn + updateFrequency;
            if (utcNow < nextUpdateDate)
            {
               return false;
            }

            if (lastUpdateEventInfo.UpdateResult == UpdateResult.NeedManualResolve)
            {
               return false;
            }
         }

         return true;
      }
        // Handles routing to additional dialogs logic.
        private async Task <DialogTurnResult> RouteStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var a     = stepContext.Context.Activity;
            var state = await _stateAccessor.GetAsync(stepContext.Context, () => new CalendarSkillState(), cancellationToken);

            state.IsAction = false;
            var options = new CalendarSkillDialogOptions()
            {
                SubFlowMode = false
            };

            if (a.Type == ActivityTypes.Message && !string.IsNullOrEmpty(a.Text))
            {
                var luisResult = stepContext.Context.TurnState.Get <CalendarLuis>(StateProperties.CalendarLuisResultKey);
                var intent     = luisResult?.TopIntent().intent;
                state.InitialIntent = intent.Value;

                var generalResult = stepContext.Context.TurnState.Get <General>(StateProperties.GeneralLuisResultKey);
                var generalIntent = generalResult?.TopIntent().intent;

                InitializeConfig(state);

                // switch on general intents
                switch (intent)
                {
                case CalendarLuis.Intent.FindMeetingRoom:
                {
                    // check whether the meeting room feature supported.
                    if (!string.IsNullOrEmpty(_settings.AzureSearch?.SearchServiceName))
                    {
                        return(await stepContext.BeginDialogAsync(_bookMeetingRoomDialog.Id, options, cancellationToken));
                    }
                    else
                    {
                        var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                        await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                    }

                    break;
                }

                case CalendarLuis.Intent.AddCalendarEntryAttribute:
                {
                    // Determine the exact intent using entities
                    if (luisResult.Entities.MeetingRoom != null || luisResult.Entities.MeetingRoomPatternAny != null || CalendarCommonUtil.ContainMeetingRoomSlot(luisResult))
                    {
                        if (!string.IsNullOrEmpty(_settings.AzureSearch?.SearchServiceName))
                        {
                            return(await stepContext.BeginDialogAsync(_updateMeetingRoomDialog.Id, options, cancellationToken));
                        }
                        else
                        {
                            var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                            await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                        }
                    }
                    else
                    {
                        var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                        await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                    }

                    break;
                }

                case CalendarLuis.Intent.CreateCalendarEntry:
                {
                    return(await stepContext.BeginDialogAsync(_createEventDialog.Id, options, cancellationToken));
                }

                case CalendarLuis.Intent.AcceptEventEntry:
                {
                    return(await stepContext.BeginDialogAsync(_changeEventStatusDialog.Id, new ChangeEventStatusDialogOptions(options, EventStatus.Accepted), cancellationToken));
                }

                case CalendarLuis.Intent.DeleteCalendarEntry:
                {
                    if (luisResult.Entities.MeetingRoom != null || luisResult.Entities.MeetingRoomPatternAny != null || CalendarCommonUtil.ContainMeetingRoomSlot(luisResult))
                    {
                        if (!string.IsNullOrEmpty(_settings.AzureSearch?.SearchServiceName))
                        {
                            return(await stepContext.BeginDialogAsync(_updateMeetingRoomDialog.Id, options, cancellationToken));
                        }
                        else
                        {
                            var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                            await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                        }
                    }
                    else
                    {
                        return(await stepContext.BeginDialogAsync(_changeEventStatusDialog.Id, new ChangeEventStatusDialogOptions(options, EventStatus.Cancelled), cancellationToken));
                    }

                    break;
                }

                case CalendarLuis.Intent.ChangeCalendarEntry:
                {
                    if (luisResult.Entities.MeetingRoom != null || luisResult.Entities.MeetingRoomPatternAny != null || CalendarCommonUtil.ContainMeetingRoomSlot(luisResult))
                    {
                        if (!string.IsNullOrEmpty(_settings.AzureSearch?.SearchServiceName))
                        {
                            return(await stepContext.BeginDialogAsync(_updateMeetingRoomDialog.Id, options, cancellationToken));
                        }
                        else
                        {
                            var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                            await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                        }
                    }
                    else
                    {
                        return(await stepContext.BeginDialogAsync(_updateEventDialog.Id, options, cancellationToken));
                    }

                    break;
                }

                case CalendarLuis.Intent.ConnectToMeeting:
                {
                    return(await stepContext.BeginDialogAsync(_joinEventDialog.Id, options, cancellationToken));
                }

                case CalendarLuis.Intent.FindCalendarEntry:
                case CalendarLuis.Intent.FindCalendarDetail:
                case CalendarLuis.Intent.FindCalendarWhen:
                case CalendarLuis.Intent.FindCalendarWhere:
                case CalendarLuis.Intent.FindCalendarWho:
                case CalendarLuis.Intent.FindDuration:
                {
                    return(await stepContext.BeginDialogAsync(_showEventsDialog.Id, new ShowMeetingsDialogOptions(ShowMeetingsDialogOptions.ShowMeetingReason.FirstShowOverview, options), cancellationToken));
                }

                case CalendarLuis.Intent.TimeRemaining:
                {
                    return(await stepContext.BeginDialogAsync(_timeRemainingDialog.Id, cancellationToken : cancellationToken));
                }

                case CalendarLuis.Intent.CheckAvailability:
                {
                    if (luisResult.Entities.MeetingRoom != null || luisResult.Entities.MeetingRoomPatternAny != null || CalendarCommonUtil.ContainMeetingRoomSlot(luisResult))
                    {
                        if (!string.IsNullOrEmpty(_settings.AzureSearch?.SearchServiceName))
                        {
                            state.InitialIntent = CalendarLuis.Intent.FindMeetingRoom;
                            return(await stepContext.BeginDialogAsync(_bookMeetingRoomDialog.Id, options, cancellationToken));
                        }
                        else
                        {
                            var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                            await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                        }
                    }
                    else
                    {
                        return(await stepContext.BeginDialogAsync(_checkPersonAvailableDialog.Id, options, cancellationToken));
                    }

                    break;
                }

                case CalendarLuis.Intent.ShowNextCalendar:
                case CalendarLuis.Intent.ShowPreviousCalendar:
                {
                    return(await stepContext.BeginDialogAsync(_showEventsDialog.Id, new ShowMeetingsDialogOptions(ShowMeetingsDialogOptions.ShowMeetingReason.FirstShowOverview, options), cancellationToken));
                }

                case CalendarLuis.Intent.None:
                {
                    if (generalIntent == General.Intent.ShowNext || generalIntent == General.Intent.ShowPrevious)
                    {
                        return(await stepContext.BeginDialogAsync(_showEventsDialog.Id, new ShowMeetingsDialogOptions(ShowMeetingsDialogOptions.ShowMeetingReason.FirstShowOverview, options), cancellationToken));
                    }
                    else
                    {
                        var activity = _templateManager.GenerateActivityForLocale(CalendarSharedResponses.DidntUnderstandMessage);
                        await stepContext.Context.SendActivityAsync(activity, cancellationToken);
                    }

                    break;
                }

                default:
                {
                    var activity = _templateManager.GenerateActivityForLocale(CalendarMainResponses.FeatureNotAvailable);
                    await stepContext.Context.SendActivityAsync(activity, cancellationToken);

                    break;
                }
                }
            }
            else if (a.Type == ActivityTypes.Event)
            {
                var ev = a.AsEventActivity();
                if (!string.IsNullOrEmpty(ev.Name))
                {
                    switch (ev.Name)
                    {
                    case Events.DeviceStart:
                    {
                        return(await stepContext.BeginDialogAsync(_upcomingEventDialog.Id, cancellationToken : cancellationToken));
                    }

                    case Events.CreateEvent:
                    {
                        state.IsAction = true;
                        EventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <EventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_createEventDialog.Id, options, cancellationToken));
                    }

                    case Events.UpdateEvent:
                    {
                        state.IsAction = true;
                        UpdateEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <UpdateEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_updateEventDialog.Id, options, cancellationToken));
                    }

                    case Events.ShowEvent:
                    {
                        state.IsAction = true;
                        ChooseEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <ChooseEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_showEventsDialog.Id, new ShowMeetingsDialogOptions(ShowMeetingsDialogOptions.ShowMeetingReason.FirstShowOverview, options), cancellationToken));
                    }

                    case Events.AcceptEvent:
                    {
                        state.IsAction = true;
                        ChooseEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <ChooseEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_changeEventStatusDialog.Id, new ChangeEventStatusDialogOptions(options, EventStatus.Accepted), cancellationToken));
                    }

                    case Events.DeleteEvent:
                    {
                        state.IsAction = true;
                        ChooseEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <ChooseEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_changeEventStatusDialog.Id, new ChangeEventStatusDialogOptions(options, EventStatus.Cancelled), cancellationToken));
                    }

                    case Events.JoinEvent:
                    {
                        state.IsAction = true;
                        ChooseEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <ChooseEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_joinEventDialog.Id, options, cancellationToken));
                    }

                    case Events.TimeRemaining:
                    {
                        state.IsAction = true;
                        ChooseEventInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <ChooseEventInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_timeRemainingDialog.Id, options, cancellationToken));
                    }

                    case Events.Summary:
                    {
                        state.IsAction = true;
                        DateInfo actionData = null;
                        if (ev.Value is JObject info)
                        {
                            actionData = info.ToObject <DateInfo>();
                            actionData.DigestState(state);
                        }

                        return(await stepContext.BeginDialogAsync(_showEventsDialog.Id, new ShowMeetingsDialogOptions(ShowMeetingsDialogOptions.ShowMeetingReason.Summary, options), cancellationToken));
                    }

                    default:
                    {
                        await stepContext.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event '{ev.Name ?? "undefined"}' was received but not processed."), cancellationToken);

                        break;
                    }
                    }
                }
            }

            // If activity was unhandled, flow should continue to next step
            return(await stepContext.NextAsync(cancellationToken : cancellationToken));
        }