protected virtual async Task ProcessEventAsync()

in libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/AdaptiveDialog.cs [447:646]


        protected virtual async Task<bool> ProcessEventAsync(ActionContext actionContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Save into turn
            actionContext.State.SetValue(TurnPath.DialogEvent, dialogEvent);

            var activity = actionContext.State.GetValue<Activity>(TurnPath.Activity);

            // some dialogevents get promoted into turn state for general access outside of the dialogevent.
            // This allows events to be fired (in the case of ChooseIntent), or in interruption (Activity) 
            // Triggers all expressed against turn.recognized or turn.activity, and this mapping maintains that 
            // any event that is emitted updates those for the rest of rule evaluation.
            switch (dialogEvent.Name)
            {
                case AdaptiveEvents.RecognizedIntent:
                    {
                        // we have received a RecognizedIntent event
                        // get the value and promote to turn.recognized, topintent,topscore and lastintent
                        var recognizedResult = actionContext.State.GetValue<RecognizerResult>($"{TurnPath.DialogEvent}.value");

                        // #3572 set these here too (Even though the emitter may have set them) because this event can be emitted by declarative code.
                        var (name, score) = recognizedResult.GetTopScoringIntent();
                        actionContext.State.SetValue(TurnPath.Recognized, recognizedResult);
                        actionContext.State.SetValue(TurnPath.TopIntent, name);
                        actionContext.State.SetValue(TurnPath.TopScore, score);
                        actionContext.State.SetValue(DialogPath.LastIntent, name);

                        // process entities for ambiguity processing (We do this regardless of who handles the event)
                        ProcessEntities(actionContext, activity);
                        break;
                    }

                case AdaptiveEvents.ActivityReceived:
                    {
                        // We received an ActivityReceived event, promote the activity into turn.activity
                        actionContext.State.SetValue(TurnPath.Activity, dialogEvent.Value);
                        activity = ObjectPath.GetPathValue<Activity>(dialogEvent, "Value");
                        break;
                    }
            }

            EnsureDependenciesInstalled();

            // Count of events processed
            var count = actionContext.State.GetValue<uint>(DialogPath.EventCounter);
            actionContext.State.SetValue(DialogPath.EventCounter, ++count);

            // Look for triggered evt
            var handled = await QueueFirstMatchAsync(actionContext, dialogEvent, cancellationToken).ConfigureAwait(false);

            if (handled)
            {
                return true;
            }

            // Default processing
            if (preBubble)
            {
                switch (dialogEvent.Name)
                {
                    case AdaptiveEvents.BeginDialog:
                        if (actionContext.State.GetBoolValue(TurnPath.ActivityProcessed) == false)
                        {
                            // Emit leading ActivityReceived event
                            var activityReceivedEvent = new DialogEvent()
                            {
                                Name = AdaptiveEvents.ActivityReceived,
                                Value = actionContext.Context.Activity,
                                Bubble = false
                            };

                            handled = await ProcessEventAsync(actionContext, dialogEvent: activityReceivedEvent, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false);
                        }

                        break;

                    case AdaptiveEvents.ActivityReceived:
                        if (activity.Type == ActivityTypes.Message)
                        {
                            // Recognize utterance (ignore handled)
                            var recognizeUtteranceEvent = new DialogEvent
                            {
                                Name = AdaptiveEvents.RecognizeUtterance,
                                Value = activity,
                                Bubble = false
                            };
                            await ProcessEventAsync(actionContext, dialogEvent: recognizeUtteranceEvent, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false);

                            // Emit leading RecognizedIntent event
                            var recognized = actionContext.State.GetValue<RecognizerResult>(TurnPath.Recognized);
                            var recognizedIntentEvent = new DialogEvent
                            {
                                Name = AdaptiveEvents.RecognizedIntent,
                                Value = recognized,
                                Bubble = false
                            };
                            handled = await ProcessEventAsync(actionContext, dialogEvent: recognizedIntentEvent, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false);
                        }

                        // Has an interruption occured?
                        // - Setting this value to true causes any running inputs to re-prompt when they're
                        //   continued.  The developer can clear this flag if they want the input to instead
                        //   process the users uterrance when its continued.
                        if (handled)
                        {
                            actionContext.State.SetValue(TurnPath.Interrupted, true);
                        }

                        break;

                    case AdaptiveEvents.RecognizeUtterance:
                        {
                            if (activity.Type == ActivityTypes.Message)
                            {
                                // Recognize utterance
                                var recognizedResult = await OnRecognizeAsync(actionContext, activity, cancellationToken).ConfigureAwait(false);

                                // TODO figure out way to not use turn state to pass this value back to caller.
                                actionContext.State.SetValue(TurnPath.Recognized, recognizedResult);

                                // Bug #3572 set these here, because if allowedInterruption is true then event is not emitted, but folks still want the value.
                                var (name, score) = recognizedResult.GetTopScoringIntent();
                                actionContext.State.SetValue(TurnPath.TopIntent, name);
                                actionContext.State.SetValue(TurnPath.TopScore, score);
                                actionContext.State.SetValue(DialogPath.LastIntent, name);

                                if (Recognizer != null)
                                {
                                    await actionContext.DebuggerStepAsync(Recognizer, AdaptiveEvents.RecognizeUtterance, cancellationToken).ConfigureAwait(false);
                                }

                                handled = true;
                            }
                        }

                        break;

                    case AdaptiveEvents.RepromptDialog:
                        {
                            // AdaptiveDialogs handle new RepromptDialog as it gives access to the dialogContext.
                            await this.RepromptDialogAsync(actionContext, actionContext.ActiveDialog, cancellationToken).ConfigureAwait(false);
                            handled = true;
                        }

                        break;
                }
            }
            else
            {
                switch (dialogEvent.Name)
                {
                    case AdaptiveEvents.BeginDialog:
                        if (actionContext.State.GetBoolValue(TurnPath.ActivityProcessed) == false)
                        {
                            var activityReceivedEvent = new DialogEvent
                            {
                                Name = AdaptiveEvents.ActivityReceived,
                                Value = activity,
                                Bubble = false
                            };

                            handled = await ProcessEventAsync(actionContext, dialogEvent: activityReceivedEvent, preBubble: false, cancellationToken: cancellationToken).ConfigureAwait(false);
                        }

                        break;

                    case AdaptiveEvents.ActivityReceived:
                        if (activity.Type == ActivityTypes.Message)
                        {
                            // Empty sequence?
                            if (!actionContext.Actions.Any())
                            {
                                // Emit trailing unknownIntent event
                                var unknownIntentEvent = new DialogEvent
                                {
                                    Name = AdaptiveEvents.UnknownIntent,
                                    Bubble = false
                                };
                                handled = await ProcessEventAsync(actionContext, dialogEvent: unknownIntentEvent, preBubble: false, cancellationToken: cancellationToken).ConfigureAwait(false);
                            }
                            else
                            {
                                handled = false;
                            }
                        }

                        // Has an interruption occured?
                        // - Setting this value to true causes any running inputs to re-prompt when they're
                        //   continued.  The developer can clear this flag if they want the input to instead
                        //   process the users uterrance when its continued.
                        if (handled)
                        {
                            actionContext.State.SetValue(TurnPath.Interrupted, true);
                        }

                        break;
                }
            }

            return handled;
        }