/// <summary>
        /// Parses a Boolean search query to produce an IQueryComponent for that query.
        /// </summary>
        /// <param name="query">query to be parsed to a query component</param>
        /// <returns>a query component</returns>
        public IQueryComponent ParseQuery(String query)
        {
            // General routine: scan the query to identify a literal, and put that literal into a list.
            //	Repeat until a + or the end of the query is encountered; build an AND query with each
            //	of the literals found. Repeat the scan-and-build-AND-query phase for each segment of the
            // query separated by + signs. In the end, build a single OR query that composes all of the built
            // AND subqueries.
            if (query == null)
            {
                return(null);
            }
            query = query.TrimStart(' ').TrimEnd(' ');
            if (query == "" || query == null)
            {
                return(null);
            }

            int start         = 0;
            var allSubqueries = new List <IQueryComponent>();

            do
            {
                // Identify the next subquery: a portion of the query up to the next + sign.
                StringBounds nextSubquery = FindNextSubquery(query, start);
                // Extract the identified subquery into its own string.
                String subquery = query.Substring(nextSubquery.Start, nextSubquery.Length);
                int    subStart = 0;

                // Store all the individual components of this subquery.
                var subqueryLiterals = new List <IQueryComponent>();

                do
                {
                    // Extract the next literal from the subquery.
                    Literal lit = FindNextLiteral(subquery, subStart);

                    // Add the literal component to the conjunctive list.
                    subqueryLiterals.Add(lit.LiteralComponent);

                    // Set the next index to start searching for a literal.
                    subStart = lit.Bounds.Start + lit.Bounds.Length;
                } while (subStart < subquery.Length);

                // After processing all literals, we are left with a list of query components that we are
                // ANDing together, and must fold that list into the final OR list of components.

                // If there was only one literal in the subquery, we don't need to AND it with anything --
                // its component can go straight into the list.
                if (subqueryLiterals.Count == 1)
                {
                    allSubqueries.Add(subqueryLiterals[0]);
                }
                else
                {
                    // With more than one literal, we must wrap them in an AndQuery component.
                    allSubqueries.Add(new AndQuery(subqueryLiterals));
                }
                start = nextSubquery.Start + nextSubquery.Length;
            } while (start < query.Length);

            // After processing all subqueries, we either have a single component or multiple components
            // that must be combined with an OrQuery.
            if (allSubqueries.Count == 1)
            {
                return(allSubqueries[0]);
            }
            else if (allSubqueries.Count > 1)
            {
                return(new OrQuery(allSubqueries));
            }
            else
            {
                return(null);
            }
        }
 public Literal(StringBounds bounds, IQueryComponent literal)
 {
     Bounds           = bounds;
     LiteralComponent = literal;
 }