/// <summary>
        /// Fills the placeholders
        /// </summary>
        /// <param name="template">Template to use</param>
        /// <param name="errorCollection">Error Collection</param>
        /// <param name="parsedData">Parsed config data</param>
        /// <param name="flexFieldObject">Flex field object to which the dialog belongs</param>
        /// <param name="valueObject">Value object to export</param>
        /// <param name="curStep">Current step that is rendered</param>
        /// <param name="nextStep">Next step that is being rendered</param>
        /// <param name="exportSettings">Export Settings</param>
        /// <param name="stepRenderer">Action Step renderer</param>
        /// <returns>Filled placeholders</returns>
        protected override async Task <string> FillPlaceholders(ExportTemplate template, ExportPlaceholderErrorCollection errorCollection, AddQuestTextData parsedData, IFlexFieldExportable valueObject, FlexFieldObject flexFieldObject,
                                                                ExportDialogData curStep, ExportDialogData nextStep, ExportSettings exportSettings, IActionStepRenderer stepRenderer)
        {
            ScribanAddQuestTextActionData actionData = new ScribanAddQuestTextActionData();

            actionData.Quest           = FlexFieldValueCollectorUtil.BuildFlexFieldValueObject <ScribanExportQuest>(null, null, valueObject, exportSettings, errorCollection);
            actionData.Text            = ExportUtil.EscapeCharacters(parsedData.QuestText, exportSettings.EscapeCharacter, exportSettings.CharactersNeedingEscaping, exportSettings.NewlineCharacter);
            actionData.UnescapedText   = parsedData.QuestText;
            actionData.TextPreview     = ExportUtil.BuildTextPreview(parsedData.QuestText);
            actionData.FlexFieldObject = flexFieldObject;
            actionData.NodeStep        = curStep;

            return(await ScribanActionRenderingUtil.FillPlaceholders(_cachedDbAccess, errorCollection, template.Code, actionData, flexFieldObject, curStep, nextStep, _scribanLanguageKeyGenerator, stepRenderer));
        }
        /// <summary>
        /// Generates a language key from a call hierarchy
        /// </summary>
        /// <param name="templateContext">Template context</param>
        /// <param name="callerContext">Call context</param>
        /// <param name="callHierarchy">Call hierarchy</param>
        /// <returns>Language key</returns>
        private async ValueTask <object> GenerateLanguageKeyFromCallHierarchy(TemplateContext templateContext, ScriptNode callerContext, List <string> callHierarchy)
        {
            if (callHierarchy.Count < 2)
            {
                _errorCollection.AddCanNotGenerateLanguageKey(ScribanErrorUtil.FormatScribanSpan(callerContext.Span));
                return("<<INVALID ARGUMENTS FOR LANGKEY>>");
            }

            string objectNameValue     = StandardMemberRenamer.Rename(nameof(ScribanFlexFieldObject.Name));
            string fieldValue          = StandardMemberRenamer.Rename(nameof(ScribanFlexFieldField.Value));
            string unescapedFieldValue = StandardMemberRenamer.Rename(nameof(ScribanFlexFieldField.UnescapedValue));
            string textLineValue       = StandardMemberRenamer.Rename(nameof(ScribanTextLine.TextLine));
            string choiceText          = StandardMemberRenamer.Rename(nameof(ScribanChoiceOption.Text));
            string addQuestText        = StandardMemberRenamer.Rename(nameof(ScribanAddQuestTextActionData.Text));
            string floatingTextData    = StandardMemberRenamer.Rename(nameof(ScribanShowFloatingTextActionData.Text));

            if (callHierarchy[callHierarchy.Count - 1] == objectNameValue || callHierarchy[callHierarchy.Count - 1] == fieldValue || callHierarchy[callHierarchy.Count - 1] == unescapedFieldValue)
            {
                ScriptNode parentObjectExpression = BuildParentObjectValueScriptExpression(callHierarchy);
                object     parentObject           = templateContext.Evaluate(parentObjectExpression);
                if (parentObject == null)
                {
                    _errorCollection.AddCanNotGenerateLanguageKey(ScribanErrorUtil.FormatScribanSpan(callerContext.Span));
                    return("<<INVALID ARGUMENTS FOR LANGKEY>>");
                }

                if (parentObject is ScribanFlexFieldObject)
                {
                    ScribanFlexFieldObject langObject = (ScribanFlexFieldObject)parentObject;
                    return(await _languageKeyGenerator.GetFlexFieldNameKey(langObject.Id, langObject.Name, langObject.ExportObjectType));
                }
                else if (parentObject is ScribanFlexFieldField)
                {
                    return(await GenerateFlexFieldLanguageKey(callerContext, (ScribanFlexFieldField)parentObject));
                }
            }
            else if (callHierarchy[callHierarchy.Count - 1] == textLineValue)
            {
                ScriptNode parentObjectExpression = BuildParentObjectValueScriptExpression(callHierarchy);
                object     parentObject           = templateContext.Evaluate(parentObjectExpression);

                if (parentObject is ScribanTextLine)
                {
                    ScribanTextLine textLine = (ScribanTextLine)parentObject;
                    return(await _languageKeyGenerator.GetDialogTextLineKey(textLine.NodeObject.Id, textLine.NodeObject.Name, textLine.IsPlayerLine?ExportConstants.LanguageKeyTypePlayer : ExportConstants.LanguageKeyTypeNpc,
                                                                            textLine.NodeId, textLine.UnescapedTextLine));
                }
            }
            else if (callHierarchy[callHierarchy.Count - 1] == choiceText || callHierarchy[callHierarchy.Count - 1] == addQuestText || callHierarchy[callHierarchy.Count - 1] == floatingTextData)
            {
                ScriptNode parentObjectExpression = BuildParentObjectValueScriptExpression(callHierarchy);
                object     parentObject           = templateContext.Evaluate(parentObjectExpression);

                if (parentObject is ScribanChoiceOption)
                {
                    ScribanChoiceOption choiceOption = (ScribanChoiceOption)parentObject;
                    return(await _languageKeyGenerator.GetDialogTextLineKey(choiceOption.ParentChoice.NodeObject.Id, choiceOption.ParentChoice.NodeObject.Name, ExportConstants.LanguageKeyTypeChoice,
                                                                            string.Format("{0}_{1}", choiceOption.ParentChoice.NodeId, choiceOption.Id), choiceOption.UnescapedText));
                }
                else if (parentObject is ScribanAddQuestTextActionData)
                {
                    ScribanAddQuestTextActionData addQuestTextData = (ScribanAddQuestTextActionData)parentObject;
                    return(await _languageKeyGenerator.GetDialogTextLineKey(addQuestTextData.FlexFieldObject.Id, addQuestTextData.Quest.Name, ExportConstants.LanguageKeyTypeQuest, addQuestTextData.NodeStep.Id,
                                                                            addQuestTextData.UnescapedText));
                }
                else if (parentObject is ScribanShowFloatingTextActionData)
                {
                    ScribanShowFloatingTextActionData showFloatingTextData = (ScribanShowFloatingTextActionData)parentObject;
                    string languageKeyType = ExportConstants.LanguageKeyTypeNpc;
                    if (showFloatingTextData.TargetNpc != null && showFloatingTextData.TargetNpc.IsPlayer)
                    {
                        languageKeyType = ExportConstants.LanguageKeyTypePlayer;
                    }
                    return(await _languageKeyGenerator.GetDialogTextLineKey(showFloatingTextData.FlexFieldObject.Id, showFloatingTextData.FlexFieldObject.Name, languageKeyType, showFloatingTextData.NodeStep.Id,
                                                                            showFloatingTextData.UnescapedText));
                }
            }

            _errorCollection.AddCanNotGenerateLanguageKey(ScribanErrorUtil.FormatScribanSpan(callerContext.Span));
            return("<<UNSUPPORTED PROPERTY FOR LANGKEY>>");
        }