/// <summary>
        /// Parses the input for optionals. The resulting collection contains only literal and optinal segments which are expanded into the full tree later by the <see cref="M:Expand"/> method.
        /// </summary>
        /// <param name="input">The input path.</param>
        /// <returns>Returns the collection of literal and optional segments.</returns>
        protected virtual PathSegmentCollection ParseOptionals(string input)
        {
            Action <StringBuilder, Stack <PathSegmentCollection> > flush = (b, s) =>
            {
                if (b.Length > 0)
                {
                    s.Peek().Add(new LiteralPathSegment(b.ToString()));
                    b.Length = 0;
                }
            };
            var sb    = new StringBuilder();
            var stack = new Stack <PathSegmentCollection>();

            stack.Push(new PathSegmentCollection());
            for (int i = 0; i < input.Length; i++)
            {
                var ch = input[i];
                if (ch == '(')
                {
                    flush(sb, stack);
                    var item = new OptionalPathSegment();
                    stack.Peek().Add(item);
                    stack.Push(item.Segments);
                }
                else if (ch == ')')
                {
                    if (stack.Count <= 1)
                    {
                        throw new FormatException("The number of closing braces is greater than the number of opening.");
                    }
                    flush(sb, stack);
                    stack.Pop();
                }
                else
                {
                    sb.Append(ch);
                }
            }
            if (stack.Count > 1)
            {
                throw new FormatException(String.Format("Missing {0} closing brace(s).", stack.Count - 1));
            }

            flush(sb, stack);
            return(stack.Peek());
        }
        /// <summary>
        /// Expands the specified segment collection which contains only optinal and literal segments.
        /// The optional segments are processed recursively and the literals are parsed for parameters.
        /// </summary>
        /// <param name="collection">The collection of segments to expand.</param>
        /// <param name="constraints">The constraints.</param>
        /// <param name="parameters">The parameters hash set to track the uniqueness.</param>
        /// <returns>Returns the expanded path segments tree.</returns>
        protected virtual PathSegmentCollection Expand(PathSegmentCollection collection, IDictionary <string, object> constraints, HashSet <string> parameters)
        {
            var result = new PathSegmentCollection();

            foreach (var item in collection)
            {
                if (item is LiteralPathSegment)
                {
                    var staticItem = (LiteralPathSegment)item;
                    var list       = Parse(staticItem.Text, constraints, parameters);
                    result.AddRange(list);
                }
                else if (item is OptionalPathSegment)
                {
                    var optItem = new OptionalPathSegment();
                    result.Add(optItem);
                    var inner = Expand(item.Segments, constraints, parameters);
                    optItem.Segments.AddRange(inner);
                }
            }
            return(result);
        }