/// <summary>
        /// Get the Objective C representation of an enum type from a string hint and the odata path segment
        /// </summary>
        /// <param name="enumHint">string representing the hint to use for enum lookup</param>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        private static string GenerateEnumString(string enumHint, ODataPathSegment pathSegment, ICollection <string> path)
        {
            IEdmType nestEdmType;

            try
            {
                nestEdmType = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);
            }
            catch (Exception)
            {
                return(string.Empty);
            }

            if (nestEdmType is IEdmEnumType edmEnumType)
            {
                var typeName = GetObjectiveCModelName(pathSegment, path);
                var temp     = enumHint.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).First();

                //look for the proper name of the enum in the members
                foreach (var member in edmEnumType.Members)
                {
                    if (temp.Equals(member.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        return($"{typeName} {member.Name}");
                    }
                }

                //if search failed default to first element
                return($"{typeName} {edmEnumType.Members.First().Name}");
            }

            //not an enum
            return(string.Empty);
        }
        /// <summary>
        /// Java specific function to generate the Enum string representation of an enum
        /// </summary>
        /// <param name="enumHint">Name of the enum needing to change to java fashion(typically camel cased)</param>
        /// <param name="pathSegment">Odata path segment containing needed parent information to know the owner of the enum</param>
        /// <param name="path">List of string showing the path of traversal through the tree structure</param>
        /// <returns>Java representation of an enum type e.g. Importance.LOW</returns>
        private static string GenerateEnumString(string enumHint, ODataPathSegment pathSegment, List <string> path)
        {
            IEdmType nestEdmType;

            try
            {
                nestEdmType = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);
            }
            catch (Exception)
            {
                return(string.Empty);
            }

            if (nestEdmType is IEdmEnumType edmEnumType)
            {
                var typeName = GetJavaClassNameFromOdataPath(pathSegment, path);
                var temp     = string.IsNullOrEmpty(enumHint) ? string.Empty : enumHint.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).First();//split in case we need to 'or' the members
                //look for the proper name of the enum in the members
                foreach (var member in edmEnumType.Members)
                {
                    if (temp.Equals(member.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        return($"{typeName}.{ GetSnakeCaseFromCamelCase(member.Name) }");
                    }
                }
                //return the enum type in uppercase java fashion
                return($"{typeName}.{ GetSnakeCaseFromCamelCase(edmEnumType.Members.First().Name) }");
            }

            return(string.Empty);
        }
        /// <summary>
        /// Return string representation of the classname for Java
        /// </summary>
        /// <param name="pathSegment">The OdataPathSegment in use</param>
        /// <param name="path">Path to follow to get find the classname</param>
        /// <returns>String representing the type in use</returns>
        private static string GetJavaClassNameFromOdataPath(ODataPathSegment pathSegment, List <string> path)
        {
            var edmType = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);

            //we need to split the string and get last item //eg microsoft.graph.data => Data
            return(CommonGenerator.UppercaseFirstLetter(edmType.ToString().Split(".").Last()));
        }
        /// <summary>
        /// Return string representation of the classname for Objective C
        /// </summary>
        /// <param name="pathSegment">The OdataPathSegment in use</param>
        /// <param name="path">Path to follow to get find the classname</param>
        /// <returns>String representing the type in use</returns>
        private static string GetObjectiveCModelName(ODataPathSegment pathSegment, ICollection <string> path)
        {
            var edmType = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);

            //we need to split the string and get last item
            //eg microsoft.graph.data => MSGraphData
            return("MSGraph" + CommonGenerator.UppercaseFirstLetter(edmType.ToString().Split(".").Last()));
        }
        /// <summary>
        /// Java specific function to check how many times a variableName has been used and append a number at the end to make it unique
        /// </summary>
        /// <param name="variableName">Variable name to be used</param>
        /// <param name="usedList">List of variable names that have been already used</param>
        private static string EnsureJavaVariableNameIsUnique(string variableName, IEnumerable <string> usedList)
        {
            var count = usedList.Count(x => x.Equals(variableName));

            if (count > 0)
            {
                return($"{variableName}{count}");                                                         //append the count to the end of string since we've used it before
            }
            return(CommonGenerator.EnsureVariableNameIsNotReserved(variableName, new JavaExpressions())); //make sure its not reserved
        }
        /// <summary>
        /// Helper function that takes in a camel case to return a snake case string in all caps for java enums
        /// </summary>
        /// <param name="camelCaseString">String that is in camel case</param>
        /// <returns>Snake case string in all caps e.g myBad => MY_BAD</returns>
        private static string GetSnakeCaseFromCamelCase(string camelCaseString)
        {
            var snakeCaseBuilder = new StringBuilder();

            foreach (var c in CommonGenerator.LowerCaseFirstLetter(camelCaseString))
            {
                if (char.IsUpper(c))
                {
                    snakeCaseBuilder.Append("_");         //insert underscore between words
                }
                snakeCaseBuilder.Append(char.ToUpper(c)); //convert the character to uppercase
            }
            return(snakeCaseBuilder.ToString());
        }
        /// <summary>
        /// Generate the snippet section for the Property segment for CSharp code as this section cannot be directly accessed in \
        /// a URL fashion
        /// </summary>
        /// <param name="snippetModel">Snippet model built from the request</param>
        private static string GeneratePropertySectionSnippet(SnippetModel snippetModel)
        {
            if (snippetModel.Segments.Count < 2)
            {
                return("");
            }

            var stringBuilder  = new StringBuilder();
            var desiredSegment = snippetModel.Segments.Last();
            var segmentIndex   = snippetModel.Segments.Count - 1;

            //move back to find first segment that is not a PropertySegment
            while ((desiredSegment is PropertySegment) && (segmentIndex > 0))
            {
                desiredSegment = snippetModel.Segments[--segmentIndex];
            }

            var selectField = snippetModel.Segments[segmentIndex + 1].Identifier;

            //generate path to the property
            var properties = "";

            while (segmentIndex < snippetModel.Segments.Count - 1)
            {
                properties = properties + "." + CommonGenerator.UppercaseFirstLetter(snippetModel.Segments[++segmentIndex].Identifier);
            }

            //modify the responseVarible name
            snippetModel.ResponseVariableName = desiredSegment.Identifier;
            var variableName    = snippetModel.Segments.Last().Identifier;
            var parentClassName = GetCsharpClassName(desiredSegment, new List <string> {
                snippetModel.ResponseVariableName
            });


            if (snippetModel.Method == HttpMethod.Get)
            {
                //we are retrieving the value
                snippetModel.SelectFieldList.Add(selectField);
                stringBuilder.Append($"\n\nvar {variableName} = {snippetModel.ResponseVariableName}{properties};");
            }
            else
            {
                //we are modifying the value
                stringBuilder.Append($"var {snippetModel.ResponseVariableName} = new {parentClassName}();");//initialise the classname
                stringBuilder.Append($"\n{snippetModel.ResponseVariableName}{properties} = {variableName};\n\n");
            }

            return(stringBuilder.ToString());
        }
        /// <summary>
        /// Generates language specific code to add special properties to the AdditionalData dictionary
        /// </summary>
        /// <param name="stringBuilder">The original string builder containing code generated so far</param>
        /// <param name="key">The odata key/property</param>
        /// <param name="value">The value related to the odata key/property</param>
        /// <param name="className">The class name for the entity needing modification</param>
        /// <param name="tabSpace">Tab space to use for formatting the code generated</param>
        /// <returns>a string builder with the relevant odata code added</returns>
        private static StringBuilder GenerateCSharpAdditionalDataSection(StringBuilder stringBuilder, string key, string value, string className, string tabSpace)
        {
            switch (key)
            {
            case "@odata.id" when className.Equals("DirectoryObject"):
                try
                {
                    var uriLastSegmentString = new Uri(value).Segments.Last();

                    uriLastSegmentString = Uri.UnescapeDataString(uriLastSegmentString);
                    stringBuilder.Append($"{tabSpace}\tId = \"{uriLastSegmentString}\",\r\n");
                }
                catch (UriFormatException)
                {
                    stringBuilder.Append($"{tabSpace}\tId = \"{value}\",\r\n");    //its not really a URI
                }
                break;

            case "@odata.type":
                var proposedType = CommonGenerator.UppercaseFirstLetter(value.Split(".").Last());
                //check if the odata type specified is different
                // maybe due to the declaration of a subclass of the type specified from the url.
                if (!className.Equals(proposedType))
                {
                    stringBuilder.Replace(className, proposedType);
                }
                break;

            default:
                //just append the property as part of the additionalData of the object
                var additionalDataString = $"{tabSpace}\tAdditionalData = new Dictionary<string, object>()\r\n{tabSpace}\t{{\r\n";
                var keyValuePairElement  = $"{tabSpace}\t\t{{\"{key}\",\"{value}\"}}";
                if (!stringBuilder.ToString().Contains(additionalDataString))    //check if we ever inserted AdditionalData to this object.
                {
                    stringBuilder.Append($"{additionalDataString}{keyValuePairElement}\r\n{tabSpace}\t}},\r\n");
                }
                else
                {
                    //insert new key value pair to already existing AdditionalData component
                    var insertionIndex = stringBuilder.ToString().IndexOf(additionalDataString, StringComparison.Ordinal) + additionalDataString.Length;
                    stringBuilder.Insert(insertionIndex, $"{keyValuePairElement},\r\n");
                }
                break;
            }

            return(stringBuilder);
        }
        /// <summary>
        /// Get the Csharp representation of an enum type from a string hint and the odata path segment
        /// </summary>
        /// <param name="enumHint">string representing the hint to use for enum lookup</param>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        private static string GenerateEnumString(string enumHint, ODataPathSegment pathSegment, ICollection <string> path)
        {
            IEdmType nestEdmType;

            try
            {
                nestEdmType = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);
            }
            catch (Exception)
            {
                return(string.Empty);
            }

            if (nestEdmType is IEdmEnumType edmEnumType)
            {
                var typeName       = GetCsharpClassName(pathSegment, path);
                var temp           = enumHint.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);//split incase we need to 'or' the members
                var enumStringList = new List <string>();

                //look for the proper name of the enum in the members
                foreach (var member in edmEnumType.Members)
                {
                    if (temp.Contains(member.Name, StringComparer.OrdinalIgnoreCase))
                    {
                        enumStringList.Add($"{typeName}.{CommonGenerator.UppercaseFirstLetter(member.Name)}");
                    }
                }

                //if search failed default to first element
                if (!enumStringList.Any())
                {
                    enumStringList.Add($"{typeName}.{CommonGenerator.UppercaseFirstLetter(edmEnumType.Members.First().Name)}");
                }

                //return the enum type "ORed" together
                return(CommonGenerator.GetListAsStringForSnippet(enumStringList, " | "));
            }

            return(string.Empty);
        }
        /// <summary>
        /// Generates language specific code to add special properties to the AdditionalData dictionary
        /// </summary>
        /// <param name="stringBuilder">The original string builder containing code generated so far</param>
        /// <param name="key">The odata key/property</param>
        /// <param name="value">The value related to the odata key/property</param>
        /// <param name="className">The class name for the entity needing modification</param>
        /// <param name="currentVarName">The variable name of the current object in use </param>
        /// <returns>a string builder with the relevant odata code added</returns>
        private static StringBuilder GenerateJavaAdditionalDataSection(StringBuilder stringBuilder, string key, string value, string className, string currentVarName)
        {
            switch (key)
            {
            case "@odata.id" when className.Equals("DirectoryObject"):
                try
                {
                    var uriLastSegmentString = new Uri(value).Segments.Last();

                    uriLastSegmentString = Uri.UnescapeDataString(uriLastSegmentString);
                    stringBuilder.Append($"{currentVarName}.Id = \"{uriLastSegmentString}\";\r\n");
                }
                catch (UriFormatException)
                {
                    stringBuilder.Append($"{currentVarName}.Id = \"{value}\";\r\n");    //its not really a URI
                }
                break;

            case "@odata.type":
                var proposedType = CommonGenerator.UppercaseFirstLetter(value.Split(".").Last());
                // check if the odata type specified is different
                // maybe due to the declaration of a subclass of the type specified from the url.
                if (!className.Equals(proposedType))
                {
                    stringBuilder.Replace(className, proposedType);
                }
                break;

            default:
                //just append the property as part of the additionalData of the object
                stringBuilder.Append($"{currentVarName}.additionalDataManager().put(\"{key}\", new JsonPrimitive(\"{value}\"));\r\n");
                break;
            }

            return(stringBuilder);
        }
        /// <summary>
        /// Java specific function that infers the return type for java that is going to be returned
        /// </summary>
        /// <param name="edmType">Definition of the type from the OData model</param>
        /// <param name="typeHint">Hint of the variable name that is coming back</param>
        /// <returns>String representing the return type</returns>
        private static string GetJavaReturnTypeName(IEdmType edmType, string typeHint)
        {
            var typeName = string.Empty;

            if (edmType is IEdmCollectionType collectionType)
            {
                if (collectionType.ElementType.Definition is IEdmNamedElement edmNamedElement)
                {
                    typeName = typeHint.Equals("delta", StringComparison.OrdinalIgnoreCase)
                        ? $"I{CommonGenerator.UppercaseFirstLetter(edmNamedElement.Name)}DeltaCollectionPage"
                        : $"I{CommonGenerator.UppercaseFirstLetter(edmNamedElement.Name)}CollectionPage";
                }
                else
                {
                    typeName = $"I{typeName}CollectionPage";
                }
            }
            else
            {
                typeName = edmType == null ? "Content": CommonGenerator.UppercaseFirstLetter(edmType.FullTypeName().Split(".").Last());
            }

            return(typeName);
        }
 /// <summary>
 /// CSharpGenerator constructor
 /// </summary>
 /// <param name="model">Model representing metadata</param>
 public CSharpGenerator(IEdmModel model)
 {
     CommonGenerator = new CommonGenerator(model);
 }
        /// <summary>
        /// Csharp function to generate Object constructor section of a code snippet. In the event that another object is needed in the middle of generation,
        /// a recursive call is made to sort out the needed object.
        /// </summary>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="jsonBody">Json string from which the information of the object to be initialized is held</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        private static string CSharpGenerateObjectFromJson(ODataPathSegment pathSegment, string jsonBody, ICollection <string> path)
        {
            var stringBuilder = new StringBuilder();
            var jsonObject    = JsonConvert.DeserializeObject(jsonBody);
            var tabSpace      = new string('\t', path.Count - 1);//d

            switch (jsonObject)
            {
            case string _:
            {
                var enumString = GenerateEnumString(jsonObject.ToString(), pathSegment, path);
                if (!string.IsNullOrEmpty(enumString))
                {
                    //Enum is accessed as the Classname then enum type e.g Importance.Low
                    stringBuilder.Append($"{tabSpace}{enumString}\r\n");
                }
                else if (jsonObject.Equals("true") || jsonObject.Equals("false"))
                {
                    stringBuilder.Append($"{tabSpace}{jsonObject}\r\n");        //boolean primitives values masquerading as strings.
                }
                else
                {
                    stringBuilder.Append($"{tabSpace}{GenerateSpecialClassString($"{jsonObject}", pathSegment, path)}");
                }
            }
            break;

            case JObject jObject:
            {
                var className = GetCsharpClassName(pathSegment, path);
                stringBuilder.Append($"new {className}\r\n");
                stringBuilder.Append($"{tabSpace}{{\r\n");        //opening curly brace
                //initialize each member/property of the object
                foreach (var(key, jToken) in jObject)
                {
                    var value   = JsonConvert.SerializeObject(jToken);
                    var newPath = path.Append(key).ToList();           //add new identifier to the path
                    if (key.Contains("@odata") || key.StartsWith("@")) //sometimes @odata maybe in the middle e.g."*****@*****.**"
                    {
                        stringBuilder = GenerateCSharpAdditionalDataSection(stringBuilder, key, jToken.Value <string>(), className, tabSpace);
                        continue;
                    }
                    switch (jToken.Type)
                    {
                    case JTokenType.Array:
                    case JTokenType.Object:
                        //new nested object needs to be constructed so call this function recursively to make it
                        var newObject = CSharpGenerateObjectFromJson(pathSegment, value, newPath);
                        stringBuilder.Append($"{tabSpace}\t{CommonGenerator.UppercaseFirstLetter(key)} = {newObject}".TrimEnd() + ",\r\n");
                        break;

                    default:
                        // we can call the function recursively to handle the other states of string/enum/special classes
                        stringBuilder.Append($"{tabSpace}\t{CommonGenerator.UppercaseFirstLetter(key)} = {CSharpGenerateObjectFromJson(pathSegment, value, newPath).Trim()},\r\n");
                        break;
                    }
                }
                //remove the trailing comma if we appended anything
                if (stringBuilder[stringBuilder.Length - 3].Equals(','))
                {
                    stringBuilder.Remove(stringBuilder.Length - 3, 1);
                }
                //closing brace
                stringBuilder.Append($"{tabSpace}}}\r\n");
            }
            break;

            case JArray array:
            {
                var objectList = array.Children <JObject>();
                var className  = GetCsharpClassName(pathSegment, path);
                stringBuilder.Append($"new List<{className}>()\r\n{tabSpace}{{\r\n");
                if (objectList.Any())
                {
                    foreach (var item in objectList)
                    {
                        var jsonString = JsonConvert.SerializeObject(item);
                        //we need to create a new object
                        var objectStringFromJson = CSharpGenerateObjectFromJson(pathSegment, jsonString, path).TrimEnd(";\r\n".ToCharArray());
                        //indent it one tab level then append it to the string builder
                        objectStringFromJson = $"{tabSpace}\t{objectStringFromJson.Replace("\r\n", "\r\n\t")}";
                        stringBuilder.Append($"{objectStringFromJson},\r\n");
                    }
                    stringBuilder.Remove(stringBuilder.Length - 3, 1); //remove the trailing comma
                }
                else                                                   //we don't have object nested but something else like empty list/strings/enums
                {
                    foreach (var element in array)
                    {
                        var listItem = CSharpGenerateObjectFromJson(pathSegment, JsonConvert.SerializeObject(element), path).TrimEnd(";\r\n".ToCharArray());
                        stringBuilder.Append($"{tabSpace}\t{listItem.TrimStart()},\r\n");
                    }
                    //remove the trailing comma if we appended anything
                    if (stringBuilder[stringBuilder.Length - 3].Equals(','))
                    {
                        stringBuilder.Remove(stringBuilder.Length - 3, 1);
                    }
                }
                stringBuilder.Append($"{tabSpace}}}\r\n");
            }
            break;

            case DateTime _:
                stringBuilder.Append($"{tabSpace}{GenerateSpecialClassString(jsonBody.Replace("\"",""), pathSegment, path)}");
                break;

            case null:
                stringBuilder.Append($"{tabSpace}null");
                break;

            default:
                var primitive = jsonObject.ToString();
                //json deserializer capitalizes the bool types so undo that
                if (primitive.Equals("True", StringComparison.Ordinal) || primitive.Equals("False", StringComparison.Ordinal))
                {
                    primitive = CommonGenerator.LowerCaseFirstLetter(primitive);
                }
                //item is a primitive print as is
                stringBuilder.Append($"{tabSpace}{primitive}\r\n");
                break;
            }

            //check if this is the outermost object in a potential nested object structure and needs the semicolon termination character.
            return(path.Count == 1 ? $"{stringBuilder.ToString().TrimEnd()};\r\n\r\n" : stringBuilder.ToString());
        }
        /// <summary>
        /// Formulates the requested Graph snippets and returns it as string for Csharp
        /// </summary>
        /// <param name="snippetModel">Model of the Snippets info <see cref="SnippetModel"/></param>
        /// <param name="languageExpressions">The language expressions to be used for code Gen</param>
        /// <returns>String of the snippet in Csharp code</returns>
        public static string GenerateCodeSnippet(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            var snippetBuilder = new StringBuilder();

            try
            {
                snippetBuilder.Append("GraphServiceClient graphClient = new GraphServiceClient( authProvider );\r\n\r\n");
                var segment = snippetModel.Segments.Last();
                snippetModel.ResponseVariableName = CommonGenerator.EnsureVariableNameIsNotReserved(snippetModel.ResponseVariableName, languageExpressions);
                //Csharp properties are uppercase so replace with list with uppercase version
                snippetModel.SelectFieldList = snippetModel.SelectFieldList.Select(CommonGenerator.UppercaseFirstLetter).ToList();
                var actions = CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions);

                //append any custom queries present
                snippetBuilder.Append(GenerateCustomQuerySection(snippetModel));

                if (snippetModel.Method == HttpMethod.Get)
                {
                    var extraSnippet = "";
                    if (segment is PropertySegment && !segment.EdmType.IsStream())//streams can be sorted out normally
                    {
                        extraSnippet = GeneratePropertySectionSnippet(snippetModel);
                        snippetModel.SelectFieldList = snippetModel.SelectFieldList.Select(CommonGenerator.UppercaseFirstLetter).ToList();
                        actions = CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions);
                    }
                    snippetBuilder.Append($"var {snippetModel.ResponseVariableName} = ");
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.GetAsync();"));
                    snippetBuilder.Append(extraSnippet);
                }
                else if (snippetModel.Method == HttpMethod.Post)
                {
                    switch (segment)
                    {
                    case NavigationPropertySegment _:
                    case EntitySetSegment _:
                    case NavigationPropertyLinkSegment _:
                        if (string.IsNullOrEmpty(snippetModel.RequestBody))
                        {
                            throw new Exception($"No request Body present for POST of entity {snippetModel.ResponseVariableName}");
                        }

                        snippetBuilder.Append($"var {snippetModel.ResponseVariableName} = ");
                        snippetBuilder.Append(CSharpGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                            snippetModel.ResponseVariableName
                        }));
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.AddAsync({snippetModel.ResponseVariableName});"));

                        break;

                    case OperationSegment _:
                        //deserialize the object since the json top level contains the list of parameter objects
                        if (JsonConvert.DeserializeObject(snippetModel.RequestBody) is JObject testObj)
                        {
                            foreach (var(key, jToken) in testObj)
                            {
                                var jsonString = JsonConvert.SerializeObject(jToken);
                                snippetBuilder.Append($"var {CommonGenerator.LowerCaseFirstLetter(key)} = ");
                                snippetBuilder.Append(CSharpGenerateObjectFromJson(segment, jsonString, new List <string> {
                                    CommonGenerator.LowerCaseFirstLetter(key)
                                }));
                            }
                        }
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.PostAsync();"));
                        break;

                    default:
                        throw new Exception("Unknown Segment Type in URI for method POST");
                    }
                }
                else if (snippetModel.Method == HttpMethod.Patch)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception($"No request Body present for Patch of entity {snippetModel.ResponseVariableName}");
                    }

                    snippetBuilder.Append($"var {snippetModel.ResponseVariableName} = ");
                    snippetBuilder.Append(CSharpGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                        snippetModel.ResponseVariableName
                    }));

                    if (segment is PropertySegment)
                    {
                        snippetBuilder.Append(GeneratePropertySectionSnippet(snippetModel));
                    }

                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.UpdateAsync({snippetModel.ResponseVariableName});"));
                }
                else if (snippetModel.Method == HttpMethod.Delete)
                {
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.DeleteAsync();"));
                }
                else if (snippetModel.Method == HttpMethod.Put)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception($"No request Body present for PUT of entity {snippetModel.ResponseVariableName}");
                    }

                    if (snippetModel.ContentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
                    {
                        snippetBuilder.Append($"var {snippetModel.ResponseVariableName} = ");
                        snippetBuilder.Append(CSharpGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                            snippetModel.ResponseVariableName
                        }));
                    }
                    else
                    {
                        snippetBuilder.Append($"var {snippetModel.ResponseVariableName} = \"{snippetModel.RequestBody.Trim()}\"\n\n");
                    }

                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{actions}\n\t.PutAsync({snippetModel.ResponseVariableName});"));
                }
                else
                {
                    throw new NotImplementedException("HTTP method not implemented for C#");
                }

                return(snippetBuilder.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// Formulates the resources part of the generated snippets
        /// </summary>
        /// <param name="snippetModel">Model of the Snippets info <see cref="SnippetModel"/></param>
        /// <returns>String of the resources in Csharp code</returns>
        private static string CSharpGenerateResourcesPath(SnippetModel snippetModel)
        {
            var resourcesPath       = new StringBuilder();
            var resourcesPathSuffix = string.Empty;

            // lets append all resources
            foreach (var item in snippetModel.Segments)
            {
                switch (item)
                {
                //handle indexing into collections
                case KeySegment keySegment:
                    resourcesPath.Append($"[\"{keySegment.Keys.FirstOrDefault().Value}\"]");
                    break;

                //handle functions/actions and any parameters present into collections
                case OperationSegment operationSegment:
                    var paramList = CommonGenerator.GetParameterListFromOperationSegment(operationSegment, snippetModel);
                    resourcesPath.Append($"\n\t.{CommonGenerator.UppercaseFirstLetter(operationSegment.Identifier)}({CommonGenerator.GetListAsStringForSnippet(paramList, ",")})");
                    break;

                case ValueSegment _:
                    resourcesPath.Append(".Content");
                    break;

                case PropertySegment propertySegment:
                    //don't append anything that is not a stream since this is not accessed directly in C#
                    if (propertySegment.EdmType.IsStream())
                    {
                        resourcesPath.Append($".{CommonGenerator.UppercaseFirstLetter(item.Identifier)}");
                    }
                    break;

                case ReferenceSegment _:
                    resourcesPath.Append(".Reference");
                    break;

                case NavigationPropertyLinkSegment _:
                    /*
                     * The ODataURIParser may sometimes not create and add a ReferenceSegment object to the end of
                     * the segments collection in the event that there is a valid NavigationPropertySegment in the
                     * collection. It will replace this NavigationPropertySegment object with a NavigationPropertyLinkSegment
                     * object. Therefore we modify the suffix so that it may be appended to show the Reference section since
                     * the $ref should always be last in a valid Odata URI.
                     */
                    if (snippetModel.Path.Contains("$ref") && !(snippetModel.Segments.Last() is ReferenceSegment))
                    {
                        var nextSegmentIndex = snippetModel.Segments.IndexOf(item) + 1;
                        if (nextSegmentIndex >= snippetModel.Segments.Count)
                        {
                            nextSegmentIndex = snippetModel.Segments.Count - 1;
                        }

                        var nextSegment = snippetModel.Segments[nextSegmentIndex];
                        //check if the next segment is a KeySegment to know if we will be accessing a single entity of a collection.
                        resourcesPathSuffix = (item.EdmType is IEdmCollectionType) && !(nextSegment is KeySegment) ? ".References" : ".Reference";
                    }
                    resourcesPath.Append($".{CommonGenerator.UppercaseFirstLetter(item.Identifier)}");
                    break;

                default:
                    //its most likely just a resource so append it
                    resourcesPath.Append($".{CommonGenerator.UppercaseFirstLetter(item.Identifier)}");
                    break;
                }
            }

            if (!string.IsNullOrEmpty(resourcesPathSuffix))
            {
                resourcesPath.Append(resourcesPathSuffix);
            }

            return(resourcesPath.ToString());
        }
        /// <summary>
        /// Formulates the requested Graph snippets and returns it as string for Objective C
        /// </summary>
        /// <param name="snippetModel">Model of the Snippets info <see cref="SnippetModel"/></param>
        /// <param name="languageExpressions">The language expressions to be used for code Gen</param>
        /// <returns>String of the snippet in Objective C code</returns>
        public static string GenerateCodeSnippet(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            StringBuilder snippetBuilder = new StringBuilder();
            var           segment        = snippetModel.Segments.Last();

            /*Auth provider section*/
            snippetBuilder.Append("MSHTTPClient *httpClient = [MSClientFactory createHTTPClientWithAuthenticationProvider:authenticationProvider];\r\n\r\n");

            /*Request generation section*/
            snippetBuilder.Append($"NSString *MSGraphBaseURL = @\"{snippetModel.ODataUriParser.ServiceRoot}\";\r\n");
            snippetBuilder.Append($"NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[MSGraphBaseURL stringByAppendingString:@\"{snippetModel.Path}{snippetModel.QueryString}\"]]];\r\n");
            snippetBuilder.Append($"[urlRequest setHTTPMethod:@\"{snippetModel.Method}\"];\r\n");

            //add header to the Request headers list so it used in the request builder
            if (snippetModel.ContentType != null)
            {
                snippetModel.RequestHeaders = snippetModel.RequestHeaders.Append(new KeyValuePair <string, IEnumerable <string> >("Content-Type", new[] { snippetModel.ContentType }));
            }

            snippetBuilder.Append(CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions));
            snippetBuilder.Append("\r\n");

            //create object to send out now that we have a payload it is not null
            if (!string.IsNullOrEmpty(snippetModel.RequestBody))
            {
                if (segment is OperationSegment)
                {
                    snippetBuilder.Append("NSMutableDictionary *payloadDictionary = [[NSMutableDictionary alloc] init];\r\n\r\n");
                    //deserialize the object since the json top level contains the list of parameter objects
                    if (JsonConvert.DeserializeObject(snippetModel.RequestBody) is JObject testObj)
                    {
                        foreach (var(key, jToken) in testObj)
                        {
                            var jsonString = JsonConvert.SerializeObject(jToken);
                            snippetBuilder.Append(ObjectiveCGenerateObjectFromJson(segment, jsonString, new List <string> {
                                CommonGenerator.LowerCaseFirstLetter(key)
                            }));
                            snippetBuilder.Append(jToken.Type == JTokenType.Array
                                ? $"payloadDictionary[@\"{key}\"] = {CommonGenerator.LowerCaseFirstLetter(key)}List;\r\n\r\n"
                                : $"payloadDictionary[@\"{key}\"] = {CommonGenerator.LowerCaseFirstLetter(key)};\r\n\r\n");
                        }
                    }
                    snippetBuilder.Append("NSData *data = [NSJSONSerialization dataWithJSONObject:payloadDictionary options:kNilOptions error:&error];\r\n");
                    snippetBuilder.Append("[urlRequest setHTTPBody:data];\r\n\r\n");
                }
                else
                {
                    snippetBuilder.Append($"{ObjectiveCGenerateObjectFromJson(snippetModel.Segments.Last(), snippetModel.RequestBody, new List<string> {snippetModel.ResponseVariableName})}\r\n");
                    snippetBuilder.Append("NSError *error;\r\n");
                    snippetBuilder.Append($"NSData *{snippetModel.ResponseVariableName}Data = [{snippetModel.ResponseVariableName} getSerializedDataWithError:&error];\r\n");
                    snippetBuilder.Append($"[urlRequest setHTTPBody:{snippetModel.ResponseVariableName}Data];\r\n\r\n");
                }
            }

            /*Task/Response generation section*/
            snippetBuilder.Append("MSURLSessionDataTask *meDataTask = [httpClient dataTaskWithRequest:urlRequest \r\n");
            snippetBuilder.Append("\tcompletionHandler: ^(NSData *data, NSURLResponse *response, NSError *nserror) {\r\n\r\n");

            //typically a GET request a json payload of the entity coming back
            if (snippetModel.Method == HttpMethod.Get)
            {
                if (segment.EdmType is IEdmCollectionType collectionType)
                {
                    //Get underlying model if it is an entity
                    if (collectionType.ElementType.Definition is IEdmNamedElement edmNamedElement)
                    {
                        snippetModel.ResponseVariableName = edmNamedElement.Name;
                    }
                    snippetBuilder.Append("\t\tNSError *jsonError = nil;\r\n");
                    snippetBuilder.Append("\t\tMSCollection *collection = [[MSCollection alloc] initWithData:data error:&jsonError];\r\n");
                    snippetBuilder.Append($"\t\tMSGraph{CommonGenerator.UppercaseFirstLetter(snippetModel.ResponseVariableName)} *{snippetModel.ResponseVariableName} " +
                                          $"= [[MSGraph{CommonGenerator.UppercaseFirstLetter(snippetModel.ResponseVariableName)} alloc] " +
                                          "initWithDictionary:[[collection value] objectAtIndex: 0] error:&nserror];\r\n\r\n");
                }
                else
                {
                    snippetBuilder.Append($"\t\tMSGraph{CommonGenerator.UppercaseFirstLetter(snippetModel.ResponseVariableName)} *{snippetModel.ResponseVariableName} " +
                                          $"= [[MSGraph{CommonGenerator.UppercaseFirstLetter(snippetModel.ResponseVariableName)} alloc] initWithData:data error:&nserror];\r\n\r\n");
                }
            }
            else
            {
                snippetBuilder.Append("\t\t//Request Completed\r\n\r\n");
            }
            snippetBuilder.Append("}];\r\n\r\n");
            snippetBuilder.Append("[meDataTask execute];");

            return(snippetBuilder.ToString());
        }
        /// <summary>
        /// Formulates the requested Graph snippets and returns it as string for Java
        /// </summary>
        /// <param name="snippetModel">Model of the Snippets info <see cref="SnippetModel"/></param>
        /// <param name="languageExpressions">The language expressions to be used for code Gen</param>
        /// <returns>String of the snippet in Java code</returns>
        public static string GenerateCodeSnippet(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            /* As the Java beta SDK is not implemented yet throw this exception till it is */
            if (snippetModel.ApiVersion.Equals("beta"))
            {
                throw new NotImplementedException("Java Beta SDK not implemented yet");
            }

            var snippetBuilder = new StringBuilder();

            try
            {
                var segment = snippetModel.Segments.Last();
                snippetModel.ResponseVariableName = CommonGenerator.EnsureVariableNameIsNotReserved(snippetModel.ResponseVariableName, languageExpressions);

                /*Auth provider section*/
                snippetBuilder.Append("IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient();\r\n\r\n");
                //append any request options present
                snippetBuilder.Append(GenerateRequestOptionsSection(snippetModel, languageExpressions));
                /*Generate the query section of the request*/
                var requestActions = CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions);

                if (snippetModel.Method == HttpMethod.Get)
                {
                    var typeName = GetJavaReturnTypeName(segment.EdmType, snippetModel.ResponseVariableName);
                    snippetBuilder.Append($"{typeName} {snippetModel.ResponseVariableName} = ");

                    if (segment is PropertySegment)
                    {
                        return(GenerateCustomRequestForPropertySegment(snippetBuilder, snippetModel));
                    }

                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.get();"));
                }
                else if (snippetModel.Method == HttpMethod.Post)
                {
                    switch (segment)
                    {
                    case NavigationPropertySegment _:
                    case EntitySetSegment _:
                    case NavigationPropertyLinkSegment _:
                        if (string.IsNullOrEmpty(snippetModel.RequestBody))
                        {
                            throw new Exception("No request Body present for Java POST request");
                        }

                        snippetBuilder.Append(JavaGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                            snippetModel.ResponseVariableName
                        }));
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.post({snippetModel.ResponseVariableName});"));
                        break;

                    case OperationSegment _:
                        //deserialize the object since the json top level contains the list of parameter objects
                        if (JsonConvert.DeserializeObject(snippetModel.RequestBody) is JObject testObj)
                        {
                            foreach (var(key, jToken) in testObj)
                            {
                                var jsonString = JsonConvert.SerializeObject(jToken);
                                snippetBuilder.Append(JavaGenerateObjectFromJson(segment, jsonString, new List <string> {
                                    CommonGenerator.LowerCaseFirstLetter(key)
                                }));
                            }
                        }
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.post();"));
                        break;

                    default:
                        throw new Exception("Unknown Segment Type in URI for method POST");
                    }
                }
                else if (snippetModel.Method == HttpMethod.Patch)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception("No request Body present for Java Patch request");
                    }

                    snippetBuilder.Append(JavaGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                        snippetModel.ResponseVariableName
                    }));

                    if (segment is PropertySegment)
                    {
                        return(GenerateCustomRequestForPropertySegment(snippetBuilder, snippetModel));
                    }

                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.patch({snippetModel.ResponseVariableName});"));
                }
                else if (snippetModel.Method == HttpMethod.Put)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception("No request Body present for Java Put request");
                    }

                    snippetBuilder.Append(JavaGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                        snippetModel.ResponseVariableName
                    }));
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.put({snippetModel.ResponseVariableName});"));
                }
                else if (snippetModel.Method == HttpMethod.Delete)
                {
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\n\t.delete();"));
                }
                else
                {
                    throw new NotImplementedException("HTTP method not implemented for Java");
                }

                return(snippetBuilder.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
Beispiel #18
0
        /// <summary>
        /// Formulates the requested Graph snippets and returns it as string for JavaScript
        /// </summary>
        /// <param name="snippetModel">Model of the Snippets info <see cref="SnippetModel"/></param>
        /// <param name="languageExpressions">The language expressions to be used for code Gen</param>
        /// <returns>String of the snippet in Javascript code</returns>
        public static string GenerateCodeSnippet(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            try
            {
                var snippetBuilder = new StringBuilder();
                snippetModel.ResponseVariableName = CommonGenerator.EnsureVariableNameIsNotReserved(snippetModel.ResponseVariableName, languageExpressions);
                //setup the auth snippet section
                snippetBuilder.Append("const options = {\n");
                snippetBuilder.Append("\tauthProvider,\n};\n\n");
                //init the client
                snippetBuilder.Append("const client = Client.init(options);\n\n");

                if (snippetModel.Method == HttpMethod.Get)
                {
                    //append any queries with the actions
                    var getActions = CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions) + "\n\t.get();";
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, getActions));
                }
                else if (snippetModel.Method == HttpMethod.Post)
                {
                    if (!string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        snippetBuilder.Append(JavascriptGenerateObjectFromJson(snippetModel.RequestBody, snippetModel.ResponseVariableName));
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, $"\n\t.post({snippetModel.ResponseVariableName});"));
                    }
                    else
                    {
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, "\n\t.post();"));
                    }
                }
                else if (snippetModel.Method == HttpMethod.Patch)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception("No body present for PATCH method in Javascript");
                    }

                    snippetBuilder.Append(JavascriptGenerateObjectFromJson(snippetModel.RequestBody, snippetModel.ResponseVariableName));
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"\n\t.update({snippetModel.ResponseVariableName});"));
                }
                else if (snippetModel.Method == HttpMethod.Delete)
                {
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, "\n\t.delete();"));
                }
                else if (snippetModel.Method == HttpMethod.Put)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new Exception("No body present for PUT method in Javascript");
                    }

                    snippetBuilder.Append(JavascriptGenerateObjectFromJson(snippetModel.RequestBody, snippetModel.ResponseVariableName));
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"\n\t.put({snippetModel.ResponseVariableName});"));
                }
                else
                {
                    throw new NotImplementedException("HTTP method not implemented for Javascript");
                }

                return(snippetBuilder.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// Generate a list of Request options and populate them as needed in a java specific function.
        /// Java does not have helper functions for all the odata parameter types and therefore the missing ones are inserted as query options here.
        /// </summary>
        /// <param name="snippetModel">Snippet model built from the request</param>
        /// <param name="languageExpressions">Language Expressions needed for the language</param>
        private static string GenerateRequestOptionsSection(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            if (!JavaModelHasRequestOptionsParameters(snippetModel))
            {
                return(string.Empty); //nothing to do here
            }
            var stringBuilder         = new StringBuilder();
            var requestOptionsPattern = "requestOptions.add(new QueryOption(\"{0}\", \"{1}\"));\r\n";

            stringBuilder.Append("LinkedList<Option> requestOptions = new LinkedList<Option>();\r\n");

            //insert any header options options
            foreach (var(key, value) in snippetModel.RequestHeaders)
            {
                if (key.ToLower().Equals("host", StringComparison.Ordinal))//no need to generate source for the host header
                {
                    continue;
                }
                //append the header to the snippet
                var valueString = value.First().Replace("\"", languageExpressions.DoubleQuotesEscapeSequence);
                stringBuilder.Append($"requestOptions.add(new HeaderOption(\"{key}\", \"{valueString}\"));\r\n");
            }

            //insert any custom query options
            foreach (var(key, value) in snippetModel.CustomQueryOptions)
            {
                stringBuilder.Append(string.Format(requestOptionsPattern, key, value));
            }

            //Append any filter queries
            if (snippetModel.FilterFieldList.Any())
            {
                var filterResult = CommonGenerator.GetListAsStringForSnippet(snippetModel.FilterFieldList, languageExpressions.FilterExpressionDelimiter);
                stringBuilder.Append(string.Format(requestOptionsPattern, "$filter", filterResult));//append the filter to the snippet
            }

            //Append any order by queries
            if (snippetModel.OrderByFieldList.Any())
            {
                var orderByResult = CommonGenerator.GetListAsStringForSnippet(snippetModel.OrderByFieldList, languageExpressions.OrderByExpressionDelimiter);
                stringBuilder.Append(string.Format(requestOptionsPattern, "$orderby", orderByResult));//append the order by result to the snippet
            }

            //Append any skip queries
            if (snippetModel.ODataUri.Skip.HasValue)
            {
                stringBuilder.Append(string.Format(requestOptionsPattern, "$skip", snippetModel.ODataUri.Skip));
            }

            //Append any search queries
            if (!string.IsNullOrEmpty(snippetModel.SearchExpression))
            {
                stringBuilder.Append(string.Format(requestOptionsPattern, "$search", snippetModel.SearchExpression));
            }

            //Append any skip token queries
            if (!string.IsNullOrEmpty(snippetModel.ODataUri.SkipToken))
            {
                stringBuilder.Append(string.Format(requestOptionsPattern, "$skiptoken", snippetModel.ODataUri.SkipToken));
            }

            //return request options section with a new line appended
            return($"{stringBuilder}\r\n");
        }
 /// <summary>
 /// ObjectiveCGenerator constructor
 /// </summary>
 /// <param name="model">Model representing metadata</param>
 public ObjectiveCGenerator(IEdmModel model)
 {
     CommonGenerator = new CommonGenerator(model);
 }
        /// <summary>
        /// Objective C function to generate Object constructor section of a code snippet. In the event that another object is needed in the middle of generation,
        /// a recursive call is made to sort out the needed object.
        /// </summary>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="jsonBody">Json string from which the information of the object to be initialized is held</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        private static string ObjectiveCGenerateObjectFromJson(ODataPathSegment pathSegment, string jsonBody, ICollection <string> path)
        {
            var stringBuilder = new StringBuilder();
            var jsonObject    = JsonConvert.DeserializeObject(jsonBody);

            switch (jsonObject)
            {
            case JObject jObject:
            {
                var className = GetObjectiveCModelName(pathSegment, path);
                stringBuilder.Append($"{className} *{path.Last()} = [[{className} alloc] init];\r\n");
                //initialize each member/property of the object
                foreach (var(key, jToken) in jObject)
                {
                    var value   = JsonConvert.SerializeObject(jToken);
                    var newPath = path.Append(key).ToList();        //add new identifier to the path
                    if (key.Contains("@odata"))
                    {
                        continue;
                    }
                    switch (jToken.Type)
                    {
                    case JTokenType.Array:
                    case JTokenType.Object:
                        //new nested object needs to be constructed so call this function recursively to make it
                        var newObject = ObjectiveCGenerateObjectFromJson(pathSegment, value, newPath).TrimEnd();
                        stringBuilder.Append($"{newObject}\r\n");
                        stringBuilder.Append(jToken.Type == JTokenType.Array
                                        ? $"[{path.Last()} set{CommonGenerator.UppercaseFirstLetter(key)}:{newPath.Last()}List];\r\n"
                                        : $"[{path.Last()} set{CommonGenerator.UppercaseFirstLetter(key)}:{newPath.Last()}];\r\n");
                        break;

                    case JTokenType.String:
                        var enumString = GenerateEnumString(jToken.ToString(), pathSegment, newPath);
                        //check if the type is an enum and handle it
                        stringBuilder.Append(!string.IsNullOrEmpty(enumString)
                                        ? $"[{path.Last()} set{CommonGenerator.UppercaseFirstLetter(key)}: [{enumString}]];\r\n"
                                        : $"[{path.Last()} set{CommonGenerator.UppercaseFirstLetter(key)}:@{value.Replace("\n", "").Replace("\r", "")}];\r\n");
                        break;

                    default:
                        stringBuilder.Append($"[{path.Last()} set{CommonGenerator.UppercaseFirstLetter(key)}: {value.Replace("\n", "").Replace("\r", "")}];\r\n");
                        break;
                    }
                }
            }
            break;

            case JArray array:
            {
                var objectList = array.Children <JObject>();
                stringBuilder.Append($"NSMutableArray *{path.Last()}List = [[NSMutableArray alloc] init];\r\n");
                if (objectList.Any())
                {
                    foreach (var item in objectList)
                    {
                        var jsonString           = JsonConvert.SerializeObject(item);
                        var objectStringFromJson = ObjectiveCGenerateObjectFromJson(pathSegment, jsonString, path).TrimEnd();
                        stringBuilder.Append($"{objectStringFromJson}\r\n");
                        stringBuilder.Append($"[{path.Last()}List addObject: {path.Last()}];\r\n");
                    }
                }
                else
                {
                    //append list of strings
                    foreach (var element in array)
                    {
                        stringBuilder.Append($"[{path.Last()}List addObject: @\"{element.Value<string>()}\"];\r\n");
                    }
                }
            }
            break;

            case string jsonString:
            {
                var enumString = GenerateEnumString(jsonString, pathSegment, path);
                if (!string.IsNullOrEmpty(enumString))
                {
                    var className = GetObjectiveCModelName(pathSegment, path);
                    stringBuilder.Append($"{className} *{path.Last()} = [{enumString}];\r\n");
                }
                else if (jsonString.Equals("true", StringComparison.OrdinalIgnoreCase))
                {
                    stringBuilder.Append($"BOOL {path.Last()} = YES;\r\n");
                }
                else if (jsonString.Equals("false", StringComparison.OrdinalIgnoreCase))
                {
                    stringBuilder.Append($"BOOL {path.Last()} = NO;\r\n");
                }
                else
                {
                    stringBuilder.Append($"NSString *{path.Last()} = @\"{jsonString}\";\r\n");
                }
            }
            break;

            case DateTime dateTime:
            {
                stringBuilder.Append($"NSString *{path.Last()}DateTimeString = @\"{dateTime.ToString(CultureInfo.InvariantCulture)}\";\r\n");
                stringBuilder.Append($"NSDate *{path.Last()} = [NSDate ms_dateFromString: {path.Last()}DateTimeString];\r\n");
            }
            break;

            case null:
                //do nothing
                break;

            default:
                var primitive = jsonObject.ToString();
                //json deserializer capitalizes the bool types so undo that
                if (primitive.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    stringBuilder.Append($"BOOL {path.Last()} = YES;\r\n");
                }
                else if (primitive.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    stringBuilder.Append($"BOOL {path.Last()} = NO;\r\n");
                }
                else
                {
                    stringBuilder.Append($"int32_t {path.Last()} = {primitive};\r\n");
                }
                break;
            }

            return(stringBuilder.ToString());
        }
Beispiel #22
0
 /// <summary>
 /// JavaGenerator constructor
 /// </summary>
 /// <param name="model">Model representing metadata</param>
 public JavaGenerator(IEdmModel model)
 {
     CommonGenerator = new CommonGenerator(model);
 }
        /// <summary>
        /// Java specific function to generate Object constructor section of a code snippet. In the event that another object is needed in the middle of generation,
        /// a recursive call is made to sort out the needed object.
        /// </summary>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="jsonString">Json string from which the information of the object to be initialized is held</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        /// <param name="usedVarNames">List to keep track of variable names used to prevent use of the same variable name</param>
        private static string JavaGenerateObjectFromJson(ODataPathSegment pathSegment, string jsonString, List <string> path, List <string> usedVarNames = null)
        {
            var stringBuilder = new StringBuilder();
            var jsonObject    = JsonConvert.DeserializeObject(jsonString);

            usedVarNames = usedVarNames ?? new List <string>();//make sure list is not null

            switch (jsonObject)
            {
            case string _:
            {
                var enumString = GenerateEnumString(jsonObject.ToString(), pathSegment, path);
                if (!string.IsNullOrEmpty(enumString))
                {
                    //Enum is accessed as the Classname then enum type e.g Importance.LOW
                    stringBuilder.Append($"{enumString.Split(".").First()} {path.Last()} = {enumString};\r\n");
                }
                else if (jsonObject.Equals("true") || jsonObject.Equals("false"))
                {
                    stringBuilder.Append($"boolean {path.Last()} = {jsonObject};\r\n");        //boolean primitives values masquerading as strings.
                }
                else
                {
                    stringBuilder.Append($"String {path.Last()} = \"{jsonObject}\";\r\n");
                }
            }
            break;

            case JObject jObject:
            {
                var currentVarName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                var className      = GetJavaClassNameFromOdataPath(pathSegment, path);
                stringBuilder.Append($"{className} { currentVarName } = new {className}();\r\n");
                //initialize each member/property of the object
                foreach (var(key, jToken) in jObject)
                {
                    var value   = JsonConvert.SerializeObject(jToken);
                    var newPath = path.Append(key).ToList();           //add new identifier to the path

                    if (key.Contains("@odata") || key.StartsWith("@")) //sometimes @odata maybe in the middle e.g."*****@*****.**"
                    {
                        stringBuilder = GenerateJavaAdditionalDataSection(stringBuilder, key, jToken.ToString(), className, currentVarName);
                        continue;
                    }
                    switch (jToken.Type)
                    {
                    case JTokenType.Array:
                    case JTokenType.Object:
                        //new nested object needs to be constructed so call this function recursively to make it
                        stringBuilder.Append($"{JavaGenerateObjectFromJson(pathSegment, value, newPath, usedVarNames)}");
                        stringBuilder.Append(jToken.Type == JTokenType.Array
                                        ? $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(newPath.Last()+"List", usedVarNames) };\r\n"
                                        : $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(newPath.Last(), usedVarNames) };\r\n");
                        break;

                    case JTokenType.String:
                        var enumString = GenerateEnumString(jToken.ToString(), pathSegment, newPath);
                        //check if the type is an enum and handle it
                        stringBuilder.Append(!string.IsNullOrEmpty(enumString)
                                        ? $"{ currentVarName }.{newPath.Last()} = {enumString};\r\n"
                                        : $"{ currentVarName }.{newPath.Last()} = {value.Replace("\n", "").Replace("\r", "")};\r\n");
                        break;

                    default:
                        stringBuilder.Append($"{ currentVarName }.{newPath.Last()} = { value.Replace("\n", "").Replace("\r", "") };\r\n");
                        break;
                    }
                    usedVarNames.Add(jToken.Type == JTokenType.Array? $"{newPath.Last()}List": newPath.Last());        //add used variable name to used list
                }
            }
            break;

            case JArray array:
            {
                var objectList = array.Children <JObject>();
                if (objectList.Any())
                {
                    var className       = GetJavaClassNameFromOdataPath(pathSegment, path);
                    var currentListName = EnsureJavaVariableNameIsUnique(path.Last() + "List", usedVarNames);
                    //Item is a list/array so declare a typed list
                    stringBuilder.Append($"LinkedList<{className}> {currentListName} = new LinkedList<{className}>();\r\n");
                    foreach (var item in objectList)
                    {
                        var currentListItemName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                        var jsonItemString      = JsonConvert.SerializeObject(item);
                        //we need to create a new object
                        var objectStringFromJson = JavaGenerateObjectFromJson(pathSegment, jsonItemString, path, usedVarNames);
                        stringBuilder.Append($"{objectStringFromJson}");
                        stringBuilder.Append($"{currentListName}.add({currentListItemName});\r\n");
                        usedVarNames.Add(path.Last());        //add used variable name to used list
                    }
                }
                else
                {
                    stringBuilder.Append($"LinkedList<String> {path.Last()}List = new LinkedList<String>();\r\n");
                    //its not nested objects but a string collection
                    foreach (var element in array)
                    {
                        stringBuilder.Append($"{path.Last()}List.add(\"{element.Value<string>()}\");\r\n");
                    }
                }
            }
            break;

            case null:
                //do nothing
                break;

            default:
                var primitive = jsonObject.ToString();
                //json deserializer capitalizes the bool types so undo that
                if (primitive.Equals("True", StringComparison.Ordinal) || primitive.Equals("False", StringComparison.Ordinal))
                {
                    stringBuilder.Append($"boolean {path.Last()} = {CommonGenerator.LowerCaseFirstLetter(primitive)};\r\n");
                }
                else
                {
                    stringBuilder.Append($"int {path.Last()} = {primitive};\r\n");    //item is a primitive print as is
                }
                break;
            }

            //check if this is the outermost object in a potential nested object structure and needs the semicolon termination character.
            return(path.Count == 1 ? $"{stringBuilder.ToString().TrimEnd()}\r\n\r\n" : stringBuilder.ToString());
        }