Models/DeploymentTemplate.cs

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
 
namespace APIManagementTemplate.Models
{
    public class DeploymentTemplate
    {
 
        [JsonProperty("$schema")]
        public string schema
        {
            get
            {
                return Constants.deploymentSchema;
            }
        }
        public string contentVersion
        {
            get
            {
                return "1.0.0.0";
            }
        }
 
        public JObject parameters { get; set; }
        public JObject variables { get; set; }
 
        public IList<JObject> resources { get; set; }
 
        public JObject outputs { get; set; }
 
        private bool parametrizePropertiesOnly { get; set; }
        private bool fixedServiceNameParameter { get; set; }
 
        public DeploymentTemplate(bool parametrizePropertiesOnly = false, bool fixedServiceNameParameter = false)
        {
            parameters = new JObject();
            variables = new JObject();
            resources = new List<JObject>();
            outputs = new JObject();
 
            this.parametrizePropertiesOnly = parametrizePropertiesOnly;
            this.fixedServiceNameParameter = fixedServiceNameParameter;
        }
 
        public static DeploymentTemplate FromString(string template)
        {
            return JsonConvert.DeserializeObject<DeploymentTemplate>(template);
        }
 
 
        public void RemoveResources_OfType(string type)
        {
            var resources = this.resources.Where(rr => rr.Value<string>("type") == type);
            int count = resources.Count();
            for (int i = 0; i < count; i++)
            {
                RemoveResource(resources.First());
            }
        }
 
 
        private void RemoveResource(JObject resource)
        {
            this.parameters.Remove(resource.Value<string>("name").Replace("[parameters('", "").Replace("')]", ""));
            this.resources.Remove(resource);
        }
 
        public string AddParameter(string paramname, string type, object defaultvalue)
        {
            return AddParameter(paramname, type, new JProperty("defaultValue", defaultvalue));
        }
 
 
        public string AddParameter(string paramname, string type, JProperty defaultvalue)
        {
            string realParameterName = paramname;
            JObject param = new JObject();
            param.Add("type", JToken.FromObject(type));
            param.Add(defaultvalue);
 
            if (this.parameters[paramname] == null)
            {
                this.parameters.Add(paramname, param);
            }
            else
            {
                if (!this.parameters[paramname].Value<string>("defaultValue").Equals(defaultvalue.Value.ToString()))
                {
                    foreach (var p in this.parameters)
                    {
                        if (p.Key.StartsWith(paramname))
                        {
                            for (int i = 2; i < 100; i++)
                            {
                                realParameterName = paramname + i.ToString();
                                if (this.parameters[realParameterName] == null)
                                {
                                    this.parameters.Add(realParameterName, param);
                                    return realParameterName;
                                }
                            }
                        }
                    }
                }
            }
            return realParameterName;
        }
        
        public string AddVariable(string variablename, string value)
        {
            string realVariableName = variablename;
 
            if (this.variables[variablename] == null)
            {
                this.variables.Add(variablename, value);
            }
            else
            {
                foreach (var p in this.variables)
                {
                    if (p.Key.StartsWith(variablename))
                    {
                        for (int i = 2; i < 100; i++)
                        {
                            realVariableName = variablename + i.ToString();
                            if (this.variables[realVariableName] == null)
                            {
                                this.variables.Add(realVariableName, value);
                                return realVariableName;
                            }
                        }
                    }
                }
            }
            return realVariableName;
        }
 
 
        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
 
        public string WrapParameterName(string paramname)
        {
            return "[parameters('" + paramname + "')]";
        }
        public string RemoveWrapParameter(string parameterstring)
        {
            return parameterstring.Replace("[parameters('", "").Replace("')]", "");
        }
 
        private string GetParameterName(string name, string ending)
        {
            if (!name.StartsWith("[parameters('"))
                return name;
 
            var tmpname = RemoveWrapParameter(name);
            if (!string.IsNullOrEmpty(ending) && tmpname.Contains(ending))
            {
                tmpname = tmpname.Substring(0, tmpname.IndexOf("_name"));
            }
            return tmpname;
        }
 
        public void AddParameterFromObject(JObject obj, string propertyName, string propertyType, string paramNamePrefix = "")
        {
 
            var propValue = (string)obj[propertyName];
            if (propValue == null || (propValue.StartsWith("[") && propValue.EndsWith("]")))
                return;
            obj[propertyName] = WrapParameterName(this.AddParameter(paramNamePrefix + "_" + propertyName, propertyType, obj[propertyName]));
        }
 
        /**
         *
         * API Management pecifics
         *
         */
 
        private bool APIMInstanceAdded = false;
        private string apimservicename;
 
        public JObject AddAPIManagementInstance(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string servicename = restObject.Value<string>("name").ToLowerInvariant();
            string type = restObject.Value<string>("type");
            apimservicename = servicename;
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = WrapParameterName(AddParameter($"{GetServiceName(servicename)}", "string", servicename));
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["sku"] = restObject["sku"];
            resource["sku"]["name"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_sku_name", "string", restObject["sku"].Value<string>("name")));
            resource["sku"]["capacity"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_sku_capacity", "string", restObject["sku"].Value<string>("capacity")));
            resource["location"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_location", "string", restObject.Value<string>("location")));
            resource["tags"] = restObject["tags"];
            resource["scale"] = null;
            resource["properties"] = new JObject();
            resource["properties"]["publisherEmail"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_publisherEmail", "string", restObject["properties"].Value<string>("publisherEmail")));
            resource["properties"]["publisherName"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_publisherName", "string", restObject["properties"].Value<string>("publisherName")));
            resource["properties"]["notificationSenderEmail"] = WrapParameterName(AddParameter($"{GetServiceName(servicename, false)}_notificationSenderEmail", "string", restObject["properties"].Value<string>("notificationSenderEmail")));
            resource["properties"]["hostnameConfigurations"] = restObject["properties"]["hostnameConfigurations"];
            resource["properties"]["additionalLocations"] = restObject["properties"]["additionalLocations"];
            resource["properties"]["virtualNetworkConfiguration"] = restObject["properties"]["virtualNetworkConfiguration"];
            resource["properties"]["customProperties"] = restObject["properties"]["customProperties"];
            resource["properties"]["virtualNetworkType"] = restObject["properties"]["virtualNetworkType"];
            this.resources.Add(resource);
            APIMInstanceAdded = true;
            return resource;
        }
 
        public string GetServiceName(string servicename, bool addName = true)
        {
            if (fixedServiceNameParameter)
                return "apimServiceName";
            return addName ? $"service_{servicename}_name" : $"service_{servicename}";
        }
 
        public JObject AddApi(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = parametrizePropertiesOnly ? $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/{name}')]" : $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/' ,parameters('{AddParameter($"api_{name}_name", "string", name)}'))]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            AddParameterFromObject((JObject)resource["properties"], "apiRevision", "string", name);
            AddParameterFromObject((JObject)resource["properties"], "serviceUrl", "string", name);
            AddParameterFromObject((JObject)resource["properties"], "apiVersion", "string", name);
            AddParameterFromObject((JObject)resource["properties"], "isCurrent", "bool", name);
             
            if (APIMInstanceAdded)
            {
                resource["dependsOn"] = new JArray(new string[] { $"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]" });
            }
            else
            {
                resource["dependsOn"] = new JArray(); ;
            }
 
            this.resources.Add(resource);
            return resource;
        }
 
        public ResourceTemplate CreateAPISchema(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
            string apiname = apiid.ValueAfter("apis");
            apiname = parametrizePropertiesOnly ? $"'{apiname}'" : $"parameters('{AddParameter($"api_{apiname}_name", "string", apiname)}')";
 
            var obj = new ResourceTemplate();
            obj.AddName($"parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}')");
            obj.AddName(apiname);
            obj.AddName($"'{name}'");
 
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.type = type;
            obj.properties = restObject.Value<JObject>("properties");
 
            if (APIMInstanceAdded)
            {
                obj.dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
                //resource["dependsOn"] = new JArray(new string[] { $"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]" });
            }
            obj.dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/apis', parameters('{GetServiceName(servicename)}'),{apiname})]");
 
            return obj;
        }
 
        public JObject CreateOperation(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
            string apiname = apiid.ValueAfter("apis");
 
            name = $"'{name}'";
            apiname = parametrizePropertiesOnly ? $"'{apiname}'" : $"parameters('{AddParameter($"api_{apiname}_name", "string", apiname)}')";
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/', {apiname}, '/', {name})]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            //Schema list
            var schemalist = new List<string>();
 
            var request = resource["properties"].Value<JObject>("request");
            if (request != null)
            {
                schemalist = schemalist.Union(FixRepresentations(request.Value<JArray>("representations"))).ToList();
            }
 
            var responses = resource["properties"].Value<JArray>("responses");
            if (responses != null)
            {
                foreach (var resp in responses)
                {
                    schemalist = schemalist.Union(FixRepresentations(resp.Value<JArray>("representations"))).ToList();
                }
            }
 
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
            }
            foreach(var schema in schemalist)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/apis/schemas', parameters('{GetServiceName(servicename)}'),{apiname},'{schema}')]");
            }
 
            dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/apis', parameters('{GetServiceName(servicename)}'),{apiname})]");
 
            resource["dependsOn"] = dependsOn;
 
            return resource;
            //this.resources.Add(resource);
        }
 
        private List<string> FixRepresentations(JArray reps)
        {
            var ll = new List<string>();
            if (reps == null)
                return ll;
            foreach (JObject rep in reps)
            {
                string sample = rep.Value<string>("sample") ?? "";
                //if sample is an arrau and start with [ it need's to be escaped
                if (sample.StartsWith("["))
                    rep["sample"] = "[" + sample;
 
                string generatedSample = rep.Value<string>("generatedSample") ?? "";
                if (generatedSample.StartsWith("["))
                    rep["generatedSample"] = "[" + generatedSample;
 
 
                var schema = rep.Value<string>("schemaId");
                if (!string.IsNullOrEmpty(schema))
                    ll.Add(schema);
            }
            return ll;
        }
 
        public Property AddBackend(JObject restObject,JObject azureResource )
        {
            Property retval = null;
            if (restObject == null)
                return retval;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/' ,'{name}')]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            if (restObject["properties"]["resourceId"] != null)
            {
                string resourceid = restObject["properties"].Value<string>("resourceId");
                var aid = new AzureResourceId(resourceid.Replace("https://management.azure.com/", ""));
                aid.SubscriptionId = "',subscription().subscriptionId,'";
                var rgparamname = AddParameter(name + "_resourceGroup", "string", aid.ResourceGroupName);
                aid.ResourceGroupName = "',parameters('" + rgparamname + "'),'";
                if (resourceid.Contains("providers/Microsoft.Logic/workflows")) //Logic App
                {
                    var laname = aid.ValueAfter("workflows");
                    var logicappname = AddParameter(name + "_logicAppName", "string", laname);
                    aid.ReplaceValueAfter("workflows", "',parameters('" + logicappname + "')");
 
 
                    var triggerObject = azureResource["properties"]["definition"].Value<JObject>("triggers");
                    string triggername = "manual";
                    foreach (var trigger in triggerObject)
                    {
                        if(trigger.Value.Value<string>("type") == "Request" && trigger.Value.Value<string>("kind") == "Http")
                        {
                            triggername = trigger.Key;
                        }
                    }
                        //need to get the Logic App triggers and find the HTTP one....
 
                    string listcallbackref = $"listCallbackUrl(resourceId(parameters('{rgparamname}'), 'Microsoft.Logic/workflows/triggers', parameters('{logicappname}'), '{triggername}'), '2017-07-01')";
 
                    resource["properties"]["url"] = $"[substring({listcallbackref}.basePath,0,add(10,indexOf({listcallbackref}.basePath,'/triggers/')))]";
                    retval = new Property()
                    {
                        type = Property.PropertyType.LogicApp,
                        name = laname.ToLower(),
                        extraInfo = listcallbackref
                    };
                }
                else if (resourceid.Contains("providers/Microsoft.Web/sites")) //Web App/Function
                {
                    var sitename = aid.ValueAfter("sites");
                    var paramsitename = AddParameter(name + "_siteName", "string", sitename);
                    aid.ReplaceValueAfter("sites", "',parameters('" + paramsitename + "')");
                    resource["properties"]["description"] = $"[parameters('{paramsitename}')]";
                    resource["properties"]["url"] = $"[concat('https://',toLower(parameters('{paramsitename}')),'.azurewebsites.net/')]";
                    retval = new Property()
                    {
                        type = Property.PropertyType.Function,
                        name = sitename.ToLower(),
                        extraInfo = $"listsecrets(resourceId(parameters('{rgparamname}'),'Microsoft.Web/sites/functions', parameters('{paramsitename}'), 'replacewithfunctionoperationname'),'2015-08-01').key"
                    };
                    var code = (resource["properties"]?["credentials"]?["query"]?.Value<JArray>("code") ?? new JArray()).FirstOrDefault();
                    if (code != null)
                    {
                        var value = code.Value<string>();
                        if (value.StartsWith("{{") && value.EndsWith("}}"))
                        {
                            var parsed = value.Substring(2, value.Length - 4);
                            dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/properties', parameters('{GetServiceName(servicename)}'),'{parsed}')]");
                        }
                    }
                }
                resource["properties"]["resourceId"] = "[concat('https://management.azure.com/','" + aid.ToString().Substring(1) + ")]";
            }
            else
            {
                AddParameterFromObject((JObject)resource["properties"], "url", "string", name);
            }
 
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
                resource["dependsOn"] = dependsOn;
            }
 
            if (this.resources.Where(rr => rr.Value<string>("name") == obj.name).Count() == 0)
                this.resources.Add(resource);
 
            return retval;
        }
        public ResourceTemplate AddVersionSet(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.AddName($"parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}')");
            obj.AddName($"'{name}'");
 
            obj.type = type;
            obj.properties = restObject.Value<JObject>("properties");
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
 
            }
            resource["dependsOn"] = dependsOn;
            this.resources.Add(resource);
            return obj;
        }
 
        public void AddGroup(JObject restObject)
        {
            if (restObject == null)
                return;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = parametrizePropertiesOnly ? $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/{name}')]" : $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/' ,parameters('{AddParameter($"group_{name}_name", "string", name)}'))]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
 
            }
            resource["dependsOn"] = dependsOn;
 
            // Avoid duplicates.
            if (this.resources.Count(rr => rr.Value<string>("name") == obj.name && rr.Value<string>("type") == obj.type) == 0)
            {
                this.resources.Add(resource);
            }
        }
 
        public JObject AddProduct(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = parametrizePropertiesOnly ? $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/{name}')]" : $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/' ,parameters('{AddParameter($"product_{name}_name", "string", name)}'))]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
 
            }
            resource["dependsOn"] = dependsOn;
 
            this.resources.Add(resource);
            return resource;
        }
 
        public JObject AddProductSubObject(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
            string productname = apiid.ValueAfter("products");
 
            productname = parametrizePropertiesOnly ? $"'{productname}'" : $"parameters('{AddParameter($"product_{productname}_name", "string", productname)}')";
            bool nonApi = type != "Microsoft.ApiManagement/service/products/apis";
            var objectname = parametrizePropertiesOnly || nonApi ? $"'{name}'" : $"parameters('{AddParameter($"api_{name}_name", "string", name)}')";
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/', {productname}, '/', {objectname})]";
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/products', parameters('{GetServiceName(servicename)}'), {productname})]");
            resource["dependsOn"] = dependsOn;
 
            return resource;
        }
 
        public ResourceTemplate AddProperty(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
            bool secret = restObject["properties"].Value<bool>("secret");
 
            AzureResourceId apiid = new AzureResourceId(restObject.Value<string>("id"));
            string servicename = apiid.ValueAfter("service");
 
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            obj.AddName($"parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}')");
            obj.AddName($"'{name}'");
 
            obj.type = type;
            obj.properties = restObject.Value<JObject>("properties");
            var resource = JObject.FromObject(obj);
 
            var propValue = resource["properties"].Value<string>("value");
            if (!(propValue == null || (propValue.StartsWith("[") && propValue.EndsWith("]"))))
            {
                resource["properties"]["value"] = WrapParameterName(this.AddParameter(restObject["properties"].Value<string>("displayName") + "_" + "value", secret ? "securestring" : "string", secret ? "secretvalue" : resource["properties"]["value"]));
            }
                 
 
             
            //AddParameterFromObject((JObject)resource["properties"], "value", secret ? "securestring" : "string", restObject["properties"].Value<string>("displayName"));
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
 
            }
            resource["dependsOn"] = dependsOn;
 
            this.resources.Add(resource);
            return obj;
        }
 
        //need to return an object with property list and so on
        public JObject CreatePolicy(JObject restObject)
        {
            if (restObject == null)
                return null;
 
            string name = restObject.Value<string>("name");
            string type = restObject.Value<string>("type");
            string servicename = "";
            string apiname = "";
            string operationname = "";
            bool servicePolicy = false;
             
            name = $"'{name}'";
 
 
            var rid = new AzureResourceId(restObject.Value<string>("id"));
            var obj = new ResourceTemplate();
            obj.comments = "Generated for resource " + restObject.Value<string>("id");
            if (type == "Microsoft.ApiManagement/service/apis/policies")
            {
                servicename = rid.ValueAfter("service");
                apiname = rid.ValueAfter("apis");
 
                apiname = parametrizePropertiesOnly ? $"'{apiname}'" : $"parameters('{AddParameter($"api_{apiname}_name", "string", apiname)}')";
                obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/', {apiname}, '/', {name})]";
            }
            else if (type == "Microsoft.ApiManagement/service/apis/operations/policies")
            {
                servicename = rid.ValueAfter("service");
                apiname = rid.ValueAfter("apis");
                operationname = rid.ValueAfter("operations");
                apiname = parametrizePropertiesOnly ? $"'{apiname}'" : $"parameters('{AddParameter($"api_{apiname}_name", "string", apiname)}')";
                operationname = $"'{operationname}'";
                obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/', {apiname}, '/', {operationname}, '/', {name})]";
            }
            else if (type == "Microsoft.ApiManagement/service/policies")
            {
                servicename = rid.ValueAfter("service");
                obj.name = $"[concat(parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}'), '/', 'policy')]";
                servicePolicy = true;
            }
 
            obj.type = type;
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
 
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
            }
 
            if (!servicePolicy)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/apis', parameters('{GetServiceName(servicename)}') , {apiname})]");
            }
 
            if (type == "Microsoft.ApiManagement/service/apis/operations/policies")
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service/apis/operations', parameters('{GetServiceName(servicename)}'), {apiname}, {operationname})]");
            }
 
            resource["dependsOn"] = dependsOn;
            return resource;
            //this.resources.Add(resource);
        }
        public JObject CreateServiceResource(JObject restObject, string resourceType, bool addResource)
        {
            var obj = new ResourceTemplate
            {
                comments = "Generated for resource " + restObject.Value<string>("id"),
                type = resourceType
            };
            var rid = new AzureResourceId(restObject.Value<string>("id"));
            var servicename = rid.ValueAfter("service");
            obj.AddName($"parameters('{AddParameter($"{GetServiceName(servicename)}", "string", servicename)}')");
            var name= restObject.Value<string>("name");
            var resourceTypeShort = GetResourceTypeShort(resourceType);
            name = parametrizePropertiesOnly ? $"'{name}'" : $"parameters('{AddParameter($"{resourceTypeShort}_{name}_name", "string", name)}')";
            obj.AddName(name);
            var resource = JObject.FromObject(obj);
            resource["properties"] = restObject["properties"];
            var dependsOn = new JArray();
            if (APIMInstanceAdded)
            {
                dependsOn.Add($"[resourceId('Microsoft.ApiManagement/service', parameters('{GetServiceName(servicename)}'))]");
            }
            resource["dependsOn"] = dependsOn;
            if (addResource)
            {
                if(resources.All(x => x.Value<string>("name") != resource.Value<string>("name")))
                    resources.Add(resource);
            }
                 
            return resource;
        }
 
        private string GetResourceTypeShort(string resourceType)
        {
            var split = resourceType.Split('/');
            var type = split[split.Length - 1];
            if (type.EndsWith("s"))
                return type.Substring(0, type.Length - 1);
            return type;
        }
 
        public JObject CreateCertificate(JObject restObject, bool addResource)
        {
            var resource = CreateServiceResource(restObject, "Microsoft.ApiManagement/service/certificates", addResource);
            var certificatename = new AzureResourceId(restObject.Value<string>("id")).ValueAfter("certificates");
            var properties = new
            {
                data = WrapParameterName(AddParameter($"certificate_{certificatename}_data", "securestring", String.Empty)),
                password = WrapParameterName(AddParameter($"certificate_{certificatename}_password", "securestring", String.Empty))
            };
            resource["properties"] = JObject.FromObject(properties);
            return resource;
        }
 
        public JObject CreateLogger(JObject restObject, bool addResource)
        {
            var resource = CreateServiceResource(restObject, "Microsoft.ApiManagement/service/loggers", addResource);
            var loggerName = new AzureResourceId(restObject.Value<string>("id")).ValueAfter("loggers");
            var credentials = resource["properties"]?["credentials"];
            if (credentials != null)
            {
                if (credentials.Value<string>("connectionString") != null)
                {
                    credentials["connectionString"] = WrapParameterName(AddParameter($"logger_{loggerName}_connectionString", "securestring", String.Empty));
                }
                if (credentials.Value<string>("name") != null)
                {
                    credentials["name"] = WrapParameterName(AddParameter($"logger_{loggerName}_credentialName", "string", GetDefaultValue(resource, "credentials", "name")));
                }
            }
            return resource;
        }
 
        public JObject CreateOpenIDConnectProvider(JObject restObject, bool addResource)
        {
            var resource = CreateServiceResource(restObject, "Microsoft.ApiManagement/service/openidConnectProviders", addResource);
            var providerName = new AzureResourceId(restObject.Value<string>("id")).ValueAfter("openidConnectProviders");
            resource["properties"]["displayName"] = WrapParameterName(AddParameter($"openidConnectProvider_{providerName}_displayname", "string", GetDefaultValue(resource, "displayName")));
            resource["properties"]["metadataEndpoint"] = WrapParameterName(AddParameter($"openidConnectProvider_{providerName}_metadataEndpoint", "string", GetDefaultValue(resource, "metadataEndpoint")));
            resource["properties"]["clientId"] = WrapParameterName(AddParameter($"openidConnectProvider_{providerName}_clientId", "string", GetDefaultValue(resource, "clientId")));
            resource["properties"]["clientSecret"] = WrapParameterName(AddParameter($"openidConnectProvider_{providerName}_clientSecret", "securestring", String.Empty));
            return resource;
        }
 
        private static string GetDefaultValue(JObject resource, params string[] names)
        {
            var prop = resource["properties"];
            foreach (var name in names)
            {
                prop = prop[name];
                if (prop == null)
                    return string.Empty;
            }
            return prop.Value<string>()??String.Empty;
        }
 
        public JObject CreateBackend(JObject restObject)
        {
            var resource = CreateServiceResource(restObject, "Microsoft.ApiManagement/service/backends", false);
            return resource;
        }
 
        public void RemoveResources_BuiltInGroups()
        {
            var groups = this.resources.Where(rr => rr.Value<string>("type") == "Microsoft.ApiManagement/service/groups" && rr["properties"].Value<string>("type") == "system");
            int count = groups.Count();
            for (int i = 0; i < count; i++)
            {
                RemoveResource(groups.First());
 
            }
        }
 
        public void ParameterizeAPIs()
        {
            var apis = this.resources.Where(rr => rr.Value<string>("type") == "Microsoft.ApiManagement/service/apis");
 
            foreach (var api in apis)
            {
 
                var name = GetParameterName(((string)api["name"]), "_name");
                AddParameterFromObject((JObject)api["properties"], "serviceUrl", "string", name);
                AddParameterFromObject((JObject)api["properties"], "apiRevision", "string", name);
            }
        }
 
        public void ParameterizeBackends()
        {
            var backends = this.resources.Where(rr => rr.Value<string>("type") == "Microsoft.ApiManagement/service/backends");
 
            foreach (var backend in backends)
            {
                var name = GetParameterName(((string)backend["name"]), "_name");
                AddParameterFromObject((JObject)backend["properties"], "url", "string", name);
 
            }
        }
 
        public void ParameterizeAuthorizationServers()
        {
            var resources = this.resources.Where(rr => rr.Value<string>("type") == "Microsoft.ApiManagement/service/authorizationServers");
 
            foreach (var resource in resources)
            {
                var name = GetParameterName(((string)resource["name"]), "_name");
                AddParameterFromObject((JObject)resource["properties"], "clientRegistrationEndpoint", "string", name);
                AddParameterFromObject((JObject)resource["properties"], "authorizationEndpoint", "string", name);
                AddParameterFromObject((JObject)resource["properties"], "tokenEndpoint", "string", name);
                AddParameterFromObject((JObject)resource["properties"], "clientSecret", "securestring", name);
                AddParameterFromObject((JObject)resource["properties"], "resourceOwnerUsername", "string", name);
                AddParameterFromObject((JObject)resource["properties"], "resourceOwnerPassword", "string", name);
 
                //handle clientid
                var orgclientidvalue = resource["properties"].Value<string>("clientId");
                var matches = System.Text.RegularExpressions.Regex.Match(orgclientidvalue, "'(?<val>[a-zA-Z0-9_-]*)'\\)\\]");
                if (matches.Groups.Count > 0)
                {
                    var orgvalue = matches.Groups["val"].Value;
                    var paramname = this.AddParameter(name + "_clientId", "securestring", orgvalue);
 
                    resource["properties"]["clientId"] = orgclientidvalue.Replace($"'{orgvalue}'", WrapParameterName(paramname));
                }
 
            }
        }
 
 
        /** PREVIEW FIXES **/
        public void FixOperationsMissingUrlTemplateParameters()
        {
 
            var resources = this.resources.Where(rr => rr.Value<string>("type") == "Microsoft.ApiManagement/service/apis/operations");
 
            foreach (var resource in resources)
            {
                string urlTemplate = resource["properties"].Value<string>("urlTemplate");
                JArray templateParameters = (JArray)resource["properties"]["templateParameters"];
                if (!string.IsNullOrEmpty(urlTemplate))
                {
                    var match = Regex.Match(urlTemplate, "{[a-zA-Z0-9_-]*}");
                    while (match.Success)
                    {
                        if (templateParameters == null)
                        {
                            templateParameters = new JArray();
                            resource["properties"]["templateParameters"] = templateParameters;
                        }
                        var name = match.Value.Replace("{", "").Replace("}", "");
                        var obj = new JObject();
                        obj.Add("name", name);
                        obj.Add("type", "string");
                        obj.Add("required", true);
                        templateParameters.Add(obj);
                        match = match.NextMatch();
                    }
                }
            }
        }
    }
}