private static Task OutputSceneFiles(Dictionary <string, CodeCompileUnit> scenes, CodeDomProvider csharp, string directoryFullName)
        {
            var prependScene = CodeGeneration_Scene.SceneClassName("Global Prepend");
            var appendScene  = CodeGeneration_Scene.SceneClassName("Global Append");
            var prepend      = scenes.Any(kvp => kvp.Key.Equals(prependScene, System.StringComparison.OrdinalIgnoreCase));
            var append       = scenes.Any(kvp => kvp.Key.Equals(appendScene, System.StringComparison.OrdinalIgnoreCase));

            return(Task.WhenAll(scenes.Select(async c =>
            {
                var type = c.Value.FirstType();
                if (!type.Name.Equals(prependScene, StringComparison.OrdinalIgnoreCase) &&
                    !type.Name.Equals(appendScene, StringComparison.OrdinalIgnoreCase))
                {
                    var interaction = c.Value.FirstType().MethodStatements(CodeConstants.SceneInteractionMethod);
                    if (interaction?.OfType <CodeSnippetStatement>().Any() ?? false)
                    {
                        var mainCall = interaction.OfType <CodeSnippetStatement>()
                                       .First(ss => ss.Value.EndsWith(CodeConstants.ScenePrimaryMethod.ToLower() + "\":"));
                        var mainInteract = interaction[interaction.IndexOf(mainCall) + 2];


                        if (prepend)
                        {
                            interaction.Insert(interaction.IndexOf(mainInteract),
                                               new CodeExpressionStatement(CodeGeneration_Navigation.GoToScene("global prepend")));
                        }

                        if (append)
                        {
                            interaction.Insert(interaction.IndexOf(mainInteract) + 1,
                                               new CodeExpressionStatement(CodeGeneration_Navigation.GoToScene("global append")));
                        }
                    }
                }

                using (var textWriter =
                           new StreamWriter(File.Open(Path.Combine(directoryFullName, c.Key.Safe()) + ".cs", FileMode.Create, FileAccess.Write)))
                {
                    csharp.GenerateCodeFromCompileUnit(
                        c.Value,
                        textWriter,
                        new System.CodeDom.Compiler.CodeGeneratorOptions());
                    await textWriter.FlushAsync();
                }
            })));
        }
        protected override Task Render(SceneInstruction instruction, CodeGeneratorContext context)
        {
            CodeStatementCollection statements;

            switch (context.CodeScope.Peek())
            {
            case CodeMemberMethod member:
                statements = member.Statements;
                break;

            case CodeTypeDeclaration codeType:
                statements = codeType.GetMainMethod().Statements;
                break;

            case CodeConditionStatement stmt:
                statements = stmt.TrueStatements;
                break;

            default:
                return(Noop(context));
            }

            CodeGeneration_Instructions.EnsureStateMaintenance(context);
            switch (instruction)
            {
            case Clear clear:
                statements.Clear(clear.Variable);
                break;

            case ClearAll clearAll:
                statements.ClearAll();
                break;

            case Decrease decrease:
                statements.Decrease(decrease.Variable, decrease.Amount);
                break;

            case Flag flag:
                statements.SetVariable(flag.Variable, true);
                break;

            case GoTo gto:
                statements.Add(CodeGeneration_Navigation.GoToScene(gto.SceneName));
                statements.Add(new CodeMethodReturnStatement());
                break;

            case GoToAndReturn goToAndReturn:
                statements.Add(CodeGeneration_Navigation.GoToScene(goToAndReturn.SceneName));
                break;

            case Increase increase:
                statements.Increase(increase.Variable, increase.Amount);
                break;

            case Set set:
                statements.SetVariable(set.Variable, set.Value);
                break;

            case SlotAssignment slotAssignment:
                context.SetSlotType(slotAssignment.SlotName, slotAssignment.SlotType);
                break;

            case Unflag unflag:
                statements.SetVariable(unflag.Variable, false);
                break;

            case End end:
                statements.Reset();
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Repeat repeat:
                statements.Add(new CodeVariableDeclarationStatement(CodeConstants.Var, "lastSpeech",
                                                                    CodeGeneration_Instructions.GetVariable("scene_lastSpeech", typeof(string), false)));
                statements.Add(new CodeMethodInvokeExpression(
                                   new CodeTypeReferenceExpression("Output"),
                                   "AddSpeech", CodeConstants.RequestVariableRef,
                                   new CodeVariableReferenceExpression("lastSpeech"), new CodePrimitiveExpression(true)));
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Restart restart:
                statements.ClearAll("scene_");
                statements.ClearAll("_scene");
                CodeGeneration_Navigation.GoToScene("start");
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Resume resume:
                statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("await Navigation"),
                                                              "Resume", CodeConstants.RequestVariableRef, new CodePrimitiveExpression(true)));
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Return returnCmd:
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Reprompt reprompt:
                statements.Add(new CodeVariableDeclarationStatement(CodeConstants.Var, "reprompt",
                                                                    CodeGeneration_Instructions.GetVariable("scene_reprompt", typeof(string), false)));
                statements.Add(new CodeMethodInvokeExpression(
                                   new CodeTypeReferenceExpression("Output"),
                                   "AddSpeech", CodeConstants.RequestVariableRef,
                                   new CodeVariableReferenceExpression("reprompt"), new CodePrimitiveExpression(true)));
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Back back:
                statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("await Navigation"),
                                                              "Back", CodeConstants.RequestVariableRef));
                statements.Add(new CodeMethodReturnStatement());
                break;

            case Pause pause:
                statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("await Navigation"),
                                                              "Pause", CodeConstants.RequestVariableRef));
                statements.Add(new CodeMethodReturnStatement());
                break;
            }
            return(base.Render(instruction, context));
        }