/// <summary>
        /// Creates a child <see cref="DialogContext"/> for the given context.
        /// </summary>
        /// <param name="dc">The <see cref="DialogContext"/> for the current turn of conversation.</param>
        /// <returns>The child <see cref="DialogContext"/> or null if no <see cref="AdaptiveDialogState.Actions"/> are found for the given context.</returns>
        public override DialogContext CreateChildContext(DialogContext dc)
        {
            var activeDialogState     = dc.ActiveDialog.State as Dictionary <string, object>;
            AdaptiveDialogState state = null;

            if (activeDialogState.TryGetValue(AdaptiveKey, out var currentState))
            {
                state = currentState as AdaptiveDialogState;
            }

            if (state == null)
            {
                state = new AdaptiveDialogState();
                activeDialogState[AdaptiveKey] = state;
            }

            if (state.Actions != null && state.Actions.Any())
            {
                var childContext = new DialogContext(this.Dialogs, dc, state.Actions.First());
                OnSetScopedServices(childContext);
                return(childContext);
            }

            return(null);
        }
        private ActionContext ToActionContext(DialogContext dc)
        {
            var activeDialogState = dc.ActiveDialog.State as Dictionary <string, object>;
            var state             = activeDialogState[AdaptiveKey] as AdaptiveDialogState;

            if (state == null)
            {
                state = new AdaptiveDialogState();
                activeDialogState[AdaptiveKey] = state;
            }

            if (state.Actions == null)
            {
                state.Actions = new List <ActionState>();
            }

            var actionContext = new ActionContext(dc.Dialogs, dc, new DialogState {
                DialogStack = dc.Stack
            }, state.Actions, changeTurnKey);

            actionContext.Parent = dc.Parent;
            return(actionContext);
        }
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} should not ever be a cancellation token");
            }

            EnsureDependenciesInstalled();

            await this.CheckForVersionChangeAsync(dc, cancellationToken).ConfigureAwait(false);

            var cardId = CardId?.GetValue(dc.State);

            var activeDialogState = dc.ActiveDialog.State as Dictionary <string, object>;

            activeDialogState[AdaptiveKey] = new AdaptiveDialogState();

            var properties = new Dictionary <string, string>()
            {
                { "DialogId", Id },
                { "Kind", Kind }
            };

            TelemetryClient.TrackEvent("AdaptiveCardDialogStart", properties);

            // select trigger
            if (!dc.State.TryGetValue <DialogEvent>("turn.dialogEvent", out DialogEvent dialogEvent))
            {
                dialogEvent = new DialogEvent {
                    Name = AdaptiveEvents.ActivityReceived, Value = dc.Context.Activity, Bubble = false
                };
                // If AdaptiveCardDialog is root dialog there may not be a dialogEvent, and conditions are
                // looking for this dialogevent as a condition.
                dc.State.SetValue("turn.dialogEvent", dialogEvent);
            }

            var actionContext = ToActionContext(dc);
            var selection     = await this.selector.SelectAsync(actionContext, cancellationToken).ConfigureAwait(false);

            if (selection.Any())
            {
                var condition = selection[0];

                await actionContext.DebuggerStepAsync(condition, dialogEvent, cancellationToken).ConfigureAwait(false);

                System.Diagnostics.Trace.TraceInformation($"Executing AdaptiveCardDialog: {Id} Rule[{condition.Id}]: {condition.GetType().Name}: {condition.GetExpression()}");

                var changes = await condition.ExecuteAsync(actionContext);

                if (changes != null && changes.Any())
                {
                    actionContext.QueueChanges(changes[0]);
                    await actionContext.ApplyChangesAsync(cancellationToken).ConfigureAwait(false);

                    var actionDC = CreateChildContext(actionContext);

                    // execute the sequence, the action should be an actionScope, so we simply start the actionAcope from the selected changelist.
                    // NOTE: We don't do any of the changelist dialog management stuff because we are always single turn response with no dialog stack.
                    var result = await actionDC.BeginDialogAsync(changes[0].Actions[0].DialogId);

                    if (result.Status == DialogTurnStatus.Waiting)
                    {
                        throw new NotSupportedException("You can't wait in an invoke activity");
                    }
                }
            }

            // --- data bind the template ----
            if (this.Template == null)
            {
                throw new Exception($"{this.Id}: a template was not provided or is not valid JSON.");
            }

            // Get data
            var data = this.Data?.GetValue(dc.State);

            if (data == null)
            {
                // template library barfs on dialogclass and class memory scopes because it tries to serialize them.
                data = dc.State.Where(kv => kv.Key != "dialogclass" && kv.Key != "class").ToDictionary(kv => kv.Key, kv2 => kv2.Value);
            }

            // bind the card and convert to JObject
            var cardJson = this.Template.Expand(data);
            var card     = !String.IsNullOrEmpty(cardJson) ? JObject.Parse(cardJson) : null;

            // stamp dialogId and cardId on all Action.Execute nodes.
            // set data.cardId = cardId on Action.Execute Nodes
            foreach (var action in card.SelectTokens("$..[?(@.type=='Action.Execute')]").OfType <JObject>())
            {
                ObjectPath.SetPathValue(action, "data.dialogId", this.Id);
                ObjectPath.SetPathValue(action, "data.cardId", cardId);
            }

            // Send invoke response (new card)
            var response = new JObject()
            {
                { "statusCode", 200 },
                { "type", AdaptiveCard.ContentType },
                { "value", card }
            };
            var activity = new Activity(type: ActivityTypesEx.InvokeResponse, value: new InvokeResponse()
            {
                Status = 200, Body = response
            });
            await dc.Context.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);

            return(await dc.EndDialogAsync(null, cancellationToken).ConfigureAwait(false));
        }