/// <summary>
        /// Generates all templates for the given <see cref="ODataPathTemplate"/>.
        /// All templates mean:
        /// 1) for key segment, we have key in parenthesis and key as segment.
        /// 2) for bound function segment, we have qualified function call and unqualified function call.
        /// </summary>
        /// <param name="path">The given path template.</param>
        /// <param name="options">The route options.</param>
        /// <returns>All path templates.</returns>
        public static IEnumerable <string> GetTemplates(this ODataPathTemplate path, ODataRouteOptions options = null)
        {
            if (path == null)
            {
                throw Error.ArgumentNull(nameof(path));
            }

            options = options ?? ODataRouteOptions.Default;

            IList <StringBuilder> templates = new List <StringBuilder>
            {
                new StringBuilder()
            };

            int count = path.Segments.Count;

            for (int index = 0; index < count; index++)
            {
                ODataSegmentTemplate segment = path.Segments[index];

                if (segment.Kind == ODataSegmentKind.Key)
                {
                    // for key segment, if it's single key, let's add key as segment template also
                    // otherwise, we only add the key in parenthesis template.
                    KeySegmentTemplate keySg = segment as KeySegmentTemplate;
                    templates = AppendKeyTemplate(templates, keySg, options);
                    continue;
                }

                if (index != 0)
                {
                    templates = CombinateTemplate(templates, "/");
                }

                // create =>  ~.../navigation/{key}/$ref
                if (segment.Kind == ODataSegmentKind.NavigationLink)
                {
                    NavigationLinkSegmentTemplate navigationLinkSegment = (NavigationLinkSegmentTemplate)segment;
                    if (index == count - 1)
                    {
                        // we don't have the other segment
                        templates = CombinateTemplates(templates, $"{navigationLinkSegment.Segment.NavigationProperty.Name}/$ref");
                    }
                    else
                    {
                        ODataSegmentTemplate nextSegment = path.Segments[index + 1];
                        if (nextSegment.Kind == ODataSegmentKind.Key)
                        {
                            // append "navigation property"
                            templates = CombinateTemplates(templates, navigationLinkSegment.Segment.NavigationProperty.Name);

                            // append "key"
                            KeySegmentTemplate keySg = nextSegment as KeySegmentTemplate;
                            templates = AppendKeyTemplate(templates, keySg, options);

                            // append $ref
                            templates = CombinateTemplates(templates, "/$ref");
                            index++; // skip the key segment after $ref.
                        }
                        else
                        {
                            templates = CombinateTemplates(templates, $"{navigationLinkSegment.Segment.NavigationProperty.Name}/$ref");
                        }
                    }

                    continue;
                }

                if (segment.Kind == ODataSegmentKind.Action)
                {
                    ActionSegmentTemplate action = (ActionSegmentTemplate)segment;
                    templates = AppendActionTemplate(templates, action, options);
                }
                else if (segment.Kind == ODataSegmentKind.Function)
                {
                    FunctionSegmentTemplate function = (FunctionSegmentTemplate)segment;
                    templates = AppendFunctionTemplate(templates, function, options);
                }
                else
                {
                    templates = CombinateTemplate(templates, segment.Literal);
                }
            }

            return(templates.Select(t => t.ToString()));
        }
        /// <summary>
        /// Generates all templates for the given <see cref="ODataPathTemplate"/>
        /// </summary>
        /// <param name="path">The given path template.</param>
        /// <returns>All path templates.</returns>
        public static IEnumerable <string> GetTemplates(this ODataPathTemplate path)
        {
            if (path == null)
            {
                throw Error.ArgumentNull(nameof(path));
            }

            IList <StringBuilder> templates = new List <StringBuilder>
            {
                new StringBuilder()
            };

            int count = path.Segments.Count;

            for (int index = 0; index < count; index++)
            {
                ODataSegmentTemplate segment = path.Segments[index];

                if (segment.Kind == ODataSegmentKind.Key)
                {
                    KeySegmentTemplate keySg = segment as KeySegmentTemplate;
                    if (keySg.Count == 1)
                    {
                        templates = CombinateTemplates(templates, "(" + segment.Literal + ")", "/" + segment.Literal);
                    }
                    else
                    {
                        templates = CombinateTemplate(templates, "(" + segment.Literal + ")");
                    }

                    continue;
                }

                if (index != 0)
                {
                    templates = CombinateTemplate(templates, "/");
                }

                // create =>  ~.../navigation/{key}/$ref
                if (segment.Kind == ODataSegmentKind.NavigationLink)
                {
                    NavigationPropertyLinkSegmentTemplate navigationLinkSegment = (NavigationPropertyLinkSegmentTemplate)segment;
                    if (index == count - 1)
                    {
                        // we don't have the other segment
                        templates = CombinateTemplates(templates, $"{navigationLinkSegment.Segment.NavigationProperty.Name}/$ref");
                    }
                    else
                    {
                        ODataSegmentTemplate nextSegment = path.Segments[index + 1];
                        if (nextSegment.Kind == ODataSegmentKind.Key)
                        {
                            // append "navigation property"
                            templates = CombinateTemplates(templates, navigationLinkSegment.Segment.NavigationProperty.Name);

                            // append "key"
                            KeySegmentTemplate keySg = nextSegment as KeySegmentTemplate;
                            if (keySg.Count == 1)
                            {
                                templates = CombinateTemplates(templates, "(" + nextSegment.Literal + ")", "/" + nextSegment.Literal);
                            }
                            else
                            {
                                templates = CombinateTemplate(templates, "(" + nextSegment.Literal + ")");
                            }

                            // append $ref
                            templates = CombinateTemplates(templates, "/$ref");
                            index++; // skip the key segment after $ref.
                        }
                        else
                        {
                            templates = CombinateTemplates(templates, $"{navigationLinkSegment.Segment.NavigationProperty.Name}/$ref");
                        }
                    }

                    continue;
                }

                if (segment.Kind == ODataSegmentKind.Action)
                {
                    ActionSegmentTemplate action = (ActionSegmentTemplate)segment;
                    templates = CombinateTemplates(templates, action.Action.FullName(), action.Action.Name);
                }
                else if (segment.Kind == ODataSegmentKind.Function)
                {
                    FunctionSegmentTemplate function = (FunctionSegmentTemplate)segment;
                    templates = CombinateTemplates(templates, function.Literal, function.UnqualifiedIdentifier);
                }
                else
                {
                    templates = CombinateTemplate(templates, segment.Literal);
                }
            }

            return(templates.Select(t => t.ToString()));
        }