public async Task <Template <MasterTemplateResources> > GenerateMasterTemplateAsync(
            string baseFilesGenerationDirectory,
            ApiTemplateResources apiTemplateResources       = null,
            PolicyTemplateResources policyTemplateResources = null,
            ApiVersionSetTemplateResources apiVersionSetTemplateResources = null,
            ProductTemplateResources productsTemplateResources            = null,
            ProductApiTemplateResources productApisTemplateResources      = null,
            TagApiTemplateResources apiTagsTemplateResources   = null,
            LoggerTemplateResources loggersTemplateResources   = null,
            BackendTemplateResources backendsTemplateResources = null,
            AuthorizationServerTemplateResources authorizationServersTemplateResources = null,
            NamedValuesResources namedValuesTemplateResources = null,
            TagTemplateResources tagTemplateResources         = null)
        {
            if (string.IsNullOrEmpty(this.extractorParameters.LinkedTemplatesBaseUrl))
            {
                this.logger.LogInformation("'{0}' is not passed. Skipping master-template generation.", nameof(this.extractorParameters.LinkedTemplatesBaseUrl));
                return(null);
            }

            this.logger.LogInformation("Started generation of master template...");

            var masterTemplate = this.masterTemplateExtractor.GenerateLinkedMasterTemplate(
                this.extractorParameters, apiTemplateResources, policyTemplateResources, apiVersionSetTemplateResources,
                productsTemplateResources, productApisTemplateResources, apiTagsTemplateResources, loggersTemplateResources,
                backendsTemplateResources, authorizationServersTemplateResources, namedValuesTemplateResources, tagTemplateResources);

            if (masterTemplate?.HasResources() == true)
            {
                await FileWriter.SaveAsJsonAsync(
                    masterTemplate,
                    directory : baseFilesGenerationDirectory,
                    fileName : this.extractorParameters.FileNames.LinkedMaster);
            }

            this.logger.LogInformation("Finished generation of master template...");
            return(masterTemplate);
        }
        public Template <MasterTemplateResources> GenerateLinkedMasterTemplate(
            ExtractorParameters extractorParameters,
            ApiTemplateResources apiTemplateResources       = null,
            PolicyTemplateResources policyTemplateResources = null,
            ApiVersionSetTemplateResources apiVersionSetTemplateResources = null,
            ProductTemplateResources productsTemplateResources            = null,
            ProductApiTemplateResources productAPIsTemplateResources      = null,
            TagApiTemplateResources apiTagsTemplateResources   = null,
            LoggerTemplateResources loggersTemplateResources   = null,
            BackendTemplateResources backendsTemplateResources = null,
            AuthorizationServerTemplateResources authorizationServersTemplateResources = null,
            NamedValuesResources namedValuesTemplateResources = null,
            TagTemplateResources tagTemplateResources         = null)
        {
            var masterTemplate = this.templateBuilder
                                 .GenerateEmptyTemplate()
                                 .Build <MasterTemplateResources>();

            masterTemplate.Parameters = this.CreateMasterTemplateParameters(extractorParameters);

            var masterResources = masterTemplate.TypedResources;
            var fileNames       = extractorParameters.FileNames;

            // all other deployment resources will depend on named values
            var dependsOnNamedValues = Array.Empty <string>();

            // api dependsOn
            var apiDependsOn        = new List <string>();
            var productApiDependsOn = new List <string>();
            var apiTagDependsOn     = new List <string>();

            if (namedValuesTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding named-values to master template");
                const string NamedValuesTemplateName = "namedValuesTemplate";

                dependsOnNamedValues = new string[] { $"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{NamedValuesTemplateName}')]" };
                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{NamedValuesTemplateName}')]");
                var namedValuesUri        = this.GenerateLinkedTemplateUri(fileNames.NamedValues, extractorParameters);
                var namedValuesDeployment = CreateLinkedMasterTemplateResourceForPropertyTemplate(
                    NamedValuesTemplateName,
                    namedValuesUri,
                    Array.Empty <string>(),
                    extractorParameters);

                masterResources.DeploymentResources.Add(namedValuesDeployment);
            }

            if (policyTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding policy to master template");
                const string GlobalServicePolicyTemplate = "globalServicePolicyTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{GlobalServicePolicyTemplate}')]");
                var globalServicePolicyUri = this.GenerateLinkedTemplateUri(fileNames.GlobalServicePolicy, extractorParameters);
                var policyDeployment       = CreateLinkedMasterTemplateResourceWithPolicyToken(
                    GlobalServicePolicyTemplate,
                    globalServicePolicyUri,
                    dependsOnNamedValues,
                    extractorParameters);

                masterResources.DeploymentResources.Add(policyDeployment);
            }

            if (apiVersionSetTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding api-version-set to master template");
                const string VersionSetTemplate = "versionSetTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{VersionSetTemplate}')]");
                string apiVersionSetUri        = this.GenerateLinkedTemplateUri(fileNames.ApiVersionSets, extractorParameters);
                var    apiVersionSetDeployment = CreateLinkedMasterTemplateResource(VersionSetTemplate, apiVersionSetUri, dependsOnNamedValues);

                masterResources.DeploymentResources.Add(apiVersionSetDeployment);
            }

            if (productsTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding products to master template");
                const string ProductsTemplate = "productsTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ProductsTemplate}')]");
                productApiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ProductsTemplate}')]");
                var productsUri = this.GenerateLinkedTemplateUri(fileNames.Products, extractorParameters);

                var productDeployment = CreateLinkedMasterTemplateResource(ProductsTemplate, productsUri, dependsOnNamedValues);

                if (!string.IsNullOrEmpty(extractorParameters.PolicyXMLBaseUrl))
                {
                    productDeployment.Properties.Parameters.Add(ParameterNames.PolicyXMLBaseUrl, new TemplateParameterProperties()
                    {
                        Value = $"[parameters('{ParameterNames.PolicyXMLBaseUrl}')]"
                    });
                }

                if (!string.IsNullOrEmpty(extractorParameters.PolicyXMLSasToken))
                {
                    productDeployment.Properties.Parameters.Add(ParameterNames.PolicyXMLSasToken, new TemplateParameterProperties()
                    {
                        Value = $"[parameters('{ParameterNames.PolicyXMLSasToken}')]"
                    });
                }

                masterResources.DeploymentResources.Add(productDeployment);
            }

            if (tagTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding tags to master template");
                const string TagTemplate = "tagTemplate";

                apiTagDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{TagTemplate}')]");
                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{TagTemplate}')]");

                var tagUri        = this.GenerateLinkedTemplateUri(fileNames.Tags, extractorParameters);
                var tagDeployment = CreateLinkedMasterTemplateResource(TagTemplate, tagUri, dependsOnNamedValues);

                masterResources.DeploymentResources.Add(tagDeployment);
            }

            if (loggersTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding loggers to master template");
                const string LoggersTemplate = "loggersTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{LoggersTemplate}')]");
                string loggersUri        = this.GenerateLinkedTemplateUri(fileNames.Loggers, extractorParameters);
                var    loggersDeployment = CreateLinkedMasterTemplateResourceForLoggerTemplate(LoggersTemplate, loggersUri, dependsOnNamedValues, extractorParameters);

                masterResources.DeploymentResources.Add(loggersDeployment);
            }

            if (backendsTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding backends to master template");
                const string BackendsTemplate = "backendsTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{BackendsTemplate}')]");
                string backendsUri        = this.GenerateLinkedTemplateUri(fileNames.Backends, extractorParameters);
                var    backendsDeployment = CreateLinkedMasterTemplateResource(BackendsTemplate, backendsUri, dependsOnNamedValues);

                if (extractorParameters.ParameterizeBackend)
                {
                    backendsDeployment.Properties.Parameters.Add(ParameterNames.BackendSettings,
                                                                 new TemplateParameterProperties()
                    {
                        Value = $"[parameters('{ParameterNames.BackendSettings}')]"
                    });
                }

                masterResources.DeploymentResources.Add(backendsDeployment);
            }

            if (authorizationServersTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding authorizationServers to master template");
                const string AuthorizationServersTemplate = "authorizationServersTemplate";

                apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{AuthorizationServersTemplate}')]");
                var authorizationServersUri        = this.GenerateLinkedTemplateUri(fileNames.AuthorizationServers, extractorParameters);
                var authorizationServersDeployment = CreateLinkedMasterTemplateResource(AuthorizationServersTemplate, authorizationServersUri, dependsOnNamedValues);

                masterResources.DeploymentResources.Add(authorizationServersDeployment);
            }

            if (apiTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding apis to master template");
                const string ApisTemplate = "apisTemplate";

                apiTagDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ApisTemplate}')]");
                productApiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ApisTemplate}')]");
                var apisUri        = this.GenerateLinkedTemplateUri(apiTemplateResources.FileName, extractorParameters);
                var apisDeployment = CreateLinkedMasterTemplateResourceForApiTemplate(ApisTemplate, apisUri, apiDependsOn.ToArray(), extractorParameters);

                masterResources.DeploymentResources.Add(apisDeployment);
            }

            if (productAPIsTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding productApis to master template");
                const string ProductApisTemplate = "productAPIsTemplate";

                var productApisUri        = this.GenerateLinkedTemplateUri(fileNames.ProductAPIs, extractorParameters);
                var productApisDeployment = CreateLinkedMasterTemplateResource(ProductApisTemplate, productApisUri, productApiDependsOn.ToArray());

                masterResources.DeploymentResources.Add(productApisDeployment);
            }

            if (apiTagsTemplateResources?.HasContent() == true)
            {
                this.logger.LogDebug("Adding apiTags to master template");
                const string ApiTagsTemplate = "apiTagsTemplate";

                var apiTagsUri        = this.GenerateLinkedTemplateUri(fileNames.TagApi, extractorParameters);
                var apiTagsDeployment = CreateLinkedMasterTemplateResource(ApiTagsTemplate, apiTagsUri, apiTagDependsOn.ToArray());

                masterResources.DeploymentResources.Add(apiTagsDeployment);
            }

            return(masterTemplate);
        }