/// ------------------------------------------------------------------------------------
        private PatternGroup CreateOuterMostPatternGroup(string pattern)
        {
            //foreach (var grp in _tokenGroups.Values.OfType<PatternGroup>().Where(g => g.Members.Count == 1))
            //    grp.GroupType = GroupType.Sequential;

            var group = new PatternGroup(_currEnvType)
            {
                GroupType = GroupType.Sequential
            };
            PatternGroupMember member = null;

            foreach (char chr in pattern)
            {
                if (chr == '+')
                {
                    if (member != null)
                    {
                        group.AddRangeOfMembers(member.CloseMember() ?? new[] { member });
                        member = null;
                    }

                    group.AddMember(new PatternGroupMember("+"));
                }
                else if (chr < kMinToken)
                {
                    (member ?? (member = new PatternGroupMember())).AddToMember(chr);
                }
                else
                {
                    if (member != null)
                    {
                        group.AddRangeOfMembers(member.CloseMember() ?? new[] { member });
                        member = null;
                    }

                    group.AddMember(_tokenGroups[chr]);
                }
            }

            if (member != null)
            {
                group.AddRangeOfMembers(member.CloseMember() ?? new[] { member });
            }

            if (group.Members.Count == 1 && group.Members[0] is PatternGroup)
            {
                group = (PatternGroup)group.Members[0];
            }

            //if (group.Members.Count == 1 && group.Members[0] is PatternGroupMember)
            //    group.GroupType = GroupType.Sequential;

            return(group);
        }
        /// ------------------------------------------------------------------------------------
        private string ParseTextInBrackets(string pattern, Match match)
        {
            var group = new PatternGroup(_currEnvType)
            {
                GroupType = GroupType.And
            };
            var symbolsInBracketedText = string.Empty;
            var bracketedText          = ParseTextBetweenOpenAndCloseSymbols(match.Result("${bracketedText}"),
                                                                             FindInnerMostBracesPair, ParseTextInBraces);

            foreach (var chr in bracketedText)
            {
                if (chr <= kMinToken)
                {
                    symbolsInBracketedText += chr;
                }
                else if (_tokenGroups[chr] is string)
                {
                    // The only time a token group is a string is when it contains a diacritic pattern cluster.
                    if (((string)_tokenGroups[chr]).Contains(App.DottedCircle))
                    {
                        group.SetDiacriticPattern((string)_tokenGroups[chr]);
                    }
                    _tokenGroups.Remove(chr);
                }
                else
                {
                    group.AddMember(_tokenGroups[chr]);
                    _tokenGroups.Remove(chr);
                }
            }

            if (symbolsInBracketedText != string.Empty)
            {
                // If plain text (i.e. not features or classes) is found between the square brackets,
                // then if it represents a single phone, that's fine. Otherwise, it's an error.
                // This deals with patterns like "[b[0*]]" (where 0 is the diacritic placeholder).
                // By the time we get here, it's assumed the SearchQueryValidator has caught errors.
                var phonesInBrackets = _project.PhoneticParser.Parse(symbolsInBracketedText, true, false);
                group.AddMember(new PatternGroupMember(phonesInBrackets[0]));
            }

            if (group.Members.Count == 1 && group.Members[0] is PatternGroup)
            {
                group = (PatternGroup)group.Members[0];
            }

            _tokenGroups[++_token] = group;
            return(ReplaceMatchedTextWithToken(pattern, match, _token));
        }
        /// ------------------------------------------------------------------------------------
        private PatternGroup ParseTextInParentheses(string text)
        {
            var subGroup = new PatternGroup(_currEnvType)
            {
                GroupType = GroupType.Sequential
            };

            foreach (var phone in _project.PhoneticParser.Parse(text, true, false))
            {
                if (phone[0] < kMinToken)
                {
                    subGroup.AddMember(new PatternGroupMember(phone));
                }
                else
                {
                    subGroup.AddMember(_tokenGroups[phone[0]]);
                    _tokenGroups.Remove(phone[0]);
                }
            }

            return(subGroup);
        }
        /// ------------------------------------------------------------------------------------
        private string ParseTextInBraces(string pattern, Match match)
        {
            var group = new PatternGroup(_currEnvType)
            {
                GroupType = GroupType.Or
            };
            var bracketedText       = match.Result("${bracketedText}");
            var piecesBetweenBraces = bracketedText.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            piecesBetweenBraces = piecesBetweenBraces.OrderByDescending(m => m.Length).ToArray();

            foreach (var piece in piecesBetweenBraces)
            {
                if (piece[0] >= kMinToken)
                {
                    group.AddMember(_tokenGroups[piece[0]]);
                    _tokenGroups.Remove(piece[0]);
                }
                else if (piece.StartsWith("(", StringComparison.Ordinal) && piece.EndsWith(")", StringComparison.Ordinal))
                {
                    group.AddMember(ParseTextInParentheses(piece.Trim('(', ')')));
                }
                else
                {
                    group.AddMember(new PatternGroupMember(piece));
                }
            }

            if (group.Members.Count == 1 && group.Members[0] is PatternGroup)
            {
                group = (PatternGroup)group.Members[0];
            }

            _tokenGroups[++_token] = group;
            return(ReplaceMatchedTextWithToken(pattern, match, _token));
        }