/// <summary>
        /// Read event queues from memory.
        /// </summary>
        /// <param name="context">Context for memory.</param>
        /// <returns>Event queues.</returns>
        public static EntityEvents Read(SequenceContext context)
        {
            var dcState = context.GetState();

            if (!dcState.TryGetValue <EntityEvents>(Events, out var queues))
            {
                queues = new EntityEvents();
            }

            return(queues);
        }
        protected async Task <DialogTurnResult> OnEndOfActionsAsync(SequenceContext sequenceContext, CancellationToken cancellationToken = default)
        {
            // End dialog and return result
            if (sequenceContext.ActiveDialog != null)
            {
                if (ShouldEnd(sequenceContext))
                {
                    RestoreParentGenerator(sequenceContext.Context);
                    sequenceContext.GetState().TryGetValue <object>(DefaultResultProperty, out var result);
                    return(await sequenceContext.EndDialogAsync(result, cancellationToken).ConfigureAwait(false));
                }

                return(EndOfTurn);
            }

            return(new DialogTurnResult(DialogTurnStatus.Cancelled));
        }
        protected async Task <bool> ProcessEventAsync(SequenceContext sequenceContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken = default)
        {
            // Save into turn
            sequenceContext.GetState().SetValue(TurnPath.DIALOGEVENT, dialogEvent);

            EnsureDependenciesInstalled();

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

            if (handled)
            {
                return(true);
            }

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

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

                    break;

                case AdaptiveEvents.ActivityReceived:

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

                        // Emit leading RecognizedIntent event
                        var recognized            = sequenceContext.GetState().GetValue <RecognizerResult>(TurnPath.RECOGNIZED);
                        var recognizedIntentEvent = new DialogEvent
                        {
                            Name   = AdaptiveEvents.RecognizedIntent,
                            Value  = recognized,
                            Bubble = false
                        };
                        handled = await ProcessEventAsync(sequenceContext, 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)
                    {
                        sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true);
                    }

                    break;

                case AdaptiveEvents.RecognizeUtterance:

                    if (sequenceContext.Context.Activity.Type == ActivityTypes.Message)
                    {
                        // Recognize utterance
                        var recognized = await OnRecognize(sequenceContext, cancellationToken).ConfigureAwait(false);

                        sequenceContext.GetState().SetValue(TurnPath.RECOGNIZED, recognized);

                        var(name, score) = recognized.GetTopScoringIntent();
                        sequenceContext.GetState().SetValue(TurnPath.TOPINTENT, name);
                        sequenceContext.GetState().SetValue(TurnPath.TOPSCORE, score);

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

                        handled = true;
                    }

                    break;
                }
            }
            else
            {
                switch (dialogEvent.Name)
                {
                case AdaptiveEvents.BeginDialog:
                    if (sequenceContext.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false)
                    {
                        var activityReceivedEvent = new DialogEvent
                        {
                            Name   = AdaptiveEvents.ActivityReceived,
                            Value  = sequenceContext.Context.Activity,
                            Bubble = false
                        };

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

                    break;

                case AdaptiveEvents.ActivityReceived:

                    var activity = sequenceContext.Context.Activity;

                    if (activity.Type == ActivityTypes.Message)
                    {
                        // Empty sequence?
                        if (!sequenceContext.Actions.Any())
                        {
                            // Emit trailing unknownIntent event
                            var unknownIntentEvent = new DialogEvent
                            {
                                Name   = AdaptiveEvents.UnknownIntent,
                                Bubble = false
                            };
                            handled = await ProcessEventAsync(sequenceContext, 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)
                    {
                        sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true);
                    }

                    break;
                }
            }

            return(handled);
        }
 /// <summary>
 /// Write state into memory.
 /// </summary>
 /// <param name="context">Memory context.</param>
 public void Write(SequenceContext context)
 => context.GetState().SetValue(Events, this);