private static IList <TemplateInfo> AppendFunctionTemplate(IList <TemplateInfo> templates, FunctionSegmentTemplate segment, ODataRouteOptions options)
        {
            Contract.Assert(segment != null);
            Contract.Assert(options != null);

            string qualified  = segment.GetDisplayName(true);
            string unqulified = segment.GetDisplayName(false);

            if (options.EnableQualifiedOperationCall && options.EnableUnqualifiedOperationCall)
            {
                return(CombinateTemplates(templates, (segment.Literal, qualified), (segment.UnqualifiedIdentifier, unqulified)));
            }
            else if (options.EnableQualifiedOperationCall)
            {
                return(CombinateTemplate(templates, (segment.Literal, qualified)));
            }
            else if (options.EnableUnqualifiedOperationCall)
            {
                return(CombinateTemplate(templates, (segment.UnqualifiedIdentifier, unqulified)));
            }
            else
            {
                throw new ODataException(Error.Format(SRResources.RouteOptionDisabledOperationSegment, "function"));
            }
        }
        private static IList <TemplateInfo> AppendKeyTemplate(IList <TemplateInfo> templates, KeySegmentTemplate segment, ODataRouteOptions options)
        {
            Contract.Assert(segment != null);
            Contract.Assert(options != null);

            string displayName = GetDisplayName(segment);

            if (options.EnableKeyInParenthesis && options.EnableKeyAsSegment)
            {
                return(CombinateTemplates(templates, ($"({segment.Literal})", $"({displayName})"), ($"/{segment.Literal}", $"/{displayName}")));
            }
            else if (options.EnableKeyInParenthesis)
            {
                return(CombinateTemplate(templates, ($"({segment.Literal})", $"({displayName})")));
            }
            else if (options.EnableKeyAsSegment)
            {
                return(CombinateTemplate(templates, ($"/{segment.Literal}", $"/{displayName}")));
            }
            else
            {
                throw new ODataException(SRResources.RouteOptionDisabledKeySegment);
            }
        }
        /// <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 template and its display name..</returns>
        public static IEnumerable <(string, string)> GetTemplates(this ODataPathTemplate path, ODataRouteOptions options = null)
        {
            if (path == null)
            {
                throw Error.ArgumentNull(nameof(path));
            }

            options = options ?? ODataRouteOptions.Default;

            IList <TemplateInfo> templates = new List <TemplateInfo>
            {
                new TemplateInfo
                {
                    Template = new StringBuilder(),
                    Display  = 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
                        string refTemp = $"{navigationLinkSegment.Segment.NavigationProperty.Name}/$ref";
                        templates = CombinateTemplates(templates, (refTemp, refTemp));
                    }
                    else
                    {
                        ODataSegmentTemplate nextSegment = path.Segments[index + 1];
                        if (nextSegment.Kind == ODataSegmentKind.Key)
                        {
                            // append "navigation property"
                            string navTemp = navigationLinkSegment.Segment.NavigationProperty.Name;
                            templates = CombinateTemplates(templates, (navTemp, navTemp));

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

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

                    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, segment.Literal));
                }
            }

            foreach (var template in templates)
            {
                yield return(template.Template.ToString(), template.Display.ToString());
            }

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