/// <summary>
        /// Helper function to make check and ensure that a variable name is not a reserved keyword for the language in use.
        /// If it is reserved, return an appropiate transformation of the variale name
        /// </summary>
        /// <param name="variableName">variable name to check for uniqueness</param>
        /// <param name="languageExpressions">Language expressions that holds list of reserved words for filtering</param>
        /// <returns>Modified variable name that is not a keyword</returns>
        public static string EnsureVariableNameIsNotReserved(string variableName, LanguageExpressions languageExpressions)
        {
            if (languageExpressions.ReservedNames.Contains(variableName))
            {
                return(languageExpressions.ReservedNameEscapeSequence + variableName);//append the language specific escape sequence
            }

            return(variableName);
        }
        /// <summary>
        /// Language agnostic function to generate Query section of code snippet
        /// </summary>
        /// <param name="snippetModel">Model of the snippet</param>
        /// <param name="languageExpressions">Instance of <see cref="LanguageExpressions"/> that holds the expressions for the specific language</param>
        public static string GenerateQuerySection(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            var snippetBuilder = new StringBuilder();

            //Append any headers section
            foreach (var(key, value) in snippetModel.RequestHeaders)
            {
                //no need to generate source for the host header
                if (key.ToLower().Equals("host", StringComparison.Ordinal))
                {
                    continue;
                }
                //append the header to the snippet
                var valueString = value.First()
                                  .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence);
                snippetBuilder.Append(string.Format(languageExpressions.HeaderExpression, key, valueString));
            }
            //Append any filter queries
            if (snippetModel.FilterFieldList.Any())
            {
                var filterResult = string.Join(languageExpressions.FilterExpressionDelimiter, snippetModel.FilterFieldList)
                                   .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence);
                //append the filter to the snippet
                snippetBuilder.Append(string.Format(languageExpressions.FilterExpression, filterResult));
            }

            //Append any search queries
            if (!string.IsNullOrEmpty(snippetModel.SearchExpression))
            {
                snippetBuilder.Append(string.Format(languageExpressions.SearchExpression,
                                                    snippetModel.SearchExpression
                                                    .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence)));
            }

            //Append the expand section
            if (!string.IsNullOrEmpty(snippetModel.ExpandFieldExpression))
            {
                //append the expand result to the snippet
                snippetBuilder.Append(string.Format(languageExpressions.ExpandExpression,
                                                    snippetModel.ExpandFieldExpression
                                                    .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence)));
            }

            //Append any select queries
            if (snippetModel.SelectFieldList.Any())
            {
                var selectResult = string.Join(languageExpressions.SelectExpressionDelimiter, snippetModel.SelectFieldList)
                                   .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence);
                //append the select result to the snippet
                snippetBuilder.Append(string.Format(languageExpressions.SelectExpression, selectResult));
            }

            //Append any orderby queries
            if (snippetModel.OrderByFieldList.Any())
            {
                var orderByResult = string.Join(languageExpressions.OrderByExpressionDelimiter, snippetModel.OrderByFieldList)
                                    .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence);
                //append the orderby result to the snippet
                snippetBuilder.Append(string.Format(languageExpressions.OrderByExpression, orderByResult));
            }

            //Append any skip queries
            if (snippetModel.ODataUri.Skip.HasValue)
            {
                snippetBuilder.Append(string.Format(languageExpressions.SkipExpression, snippetModel.ODataUri.Skip));
            }

            //Append any skip token queries
            if (!string.IsNullOrEmpty(snippetModel.ODataUri.SkipToken))
            {
                snippetBuilder.Append(string.Format(languageExpressions.SkipTokenExpression,
                                                    snippetModel.ODataUri.SkipToken
                                                    .EscapeQuotesInLiteral(languageExpressions.DoubleQuotesEscapeSequence, languageExpressions.SingleQuotesEscapeSequence)));
            }

            //Append any top queries
            if (snippetModel.ODataUri.Top.HasValue)
            {
                snippetBuilder.Append(string.Format(languageExpressions.TopExpression, snippetModel.ODataUri.Top));
            }

            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 string GenerateCodeSnippet(SnippetModel snippetModel, LanguageExpressions languageExpressions)
        {
            var snippetBuilder = new StringBuilder();

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

                /*Auth provider section*/
                snippetBuilder.Append("GraphServiceClient 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);
                    snippetBuilder.Append($"{typeName} {snippetModel.ResponseVariableName} = ");

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

                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\r\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}\r\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}\r\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}\r\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");
                    }

                    if (snippetModel.ContentType?.Contains("json") ?? false)
                    {
                        snippetBuilder.Append(JavaGenerateObjectFromJson(segment, snippetModel.RequestBody, new List <string> {
                            snippetModel.ResponseVariableName
                        }));
                    }
                    else
                    {
                        snippetBuilder.Append($"byte[] {snippetModel.ResponseVariableName} = Base64.getDecoder().decode({AddQuotesIfMising(snippetModel.RequestBody?.Replace("\n", string.Empty)?.Replace("\r", string.Empty))});\r\n\t");
                    }
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\r\n\t.put({snippetModel.ResponseVariableName});"));
                }
                else if (snippetModel.Method == HttpMethod.Delete)
                {
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"{requestActions}\r\n\t.delete();"));
                }
                else
                {
                    throw new NotImplementedException("HTTP method not implemented for Java");
                }

                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 search queries
            if (!string.IsNullOrEmpty(snippetModel.SearchExpression))
            {
                stringBuilder.Append(string.Format(requestOptionsPattern, "$search", snippetModel.SearchExpression));
            }

            //return request options section with a new line appended
            return($"{stringBuilder}\r\n");
        }
        /// <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 = {\r\n");
                snippetBuilder.Append("\tauthProvider,\r\n};\r\n\r\n");
                //init the client
                snippetBuilder.Append("const client = Client.init(options);\r\n\r\n");

                if (snippetModel.Method == HttpMethod.Get)
                {
                    //append any queries with the actions
                    snippetBuilder.Append($"let {snippetModel.ResponseVariableName} = ");
                    var getActions = CommonGenerator.GenerateQuerySection(snippetModel, languageExpressions) + "\r\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, $"\r\n\t.post({snippetModel.ResponseVariableName});"));
                    }
                    else
                    {
                        snippetBuilder.Append(GenerateRequestSection(snippetModel, "\r\n\t.post();"));
                    }
                }
                else if (snippetModel.Method == HttpMethod.Patch)
                {
                    if (string.IsNullOrEmpty(snippetModel.RequestBody))
                    {
                        throw new ArgumentException("No body present for PATCH method in Javascript");
                    }

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

                    snippetBuilder.Append(JavascriptGenerateObjectFromJson(snippetModel.RequestBody, snippetModel.ResponseVariableName));
                    snippetBuilder.Append(GenerateRequestSection(snippetModel, $"\r\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);
            }
        }