#ifndef _QueryParser_h_
#define _QueryParser_h_

#include "htString.h"
#include "Query.h"

//
// query lexer
// abstract class
//
// defines terminal symbols 'end' and 'quote'
// Set() sets the query string and advances to first token
// Next() advances to next token
//
class QueryLexer
{
public:
	virtual ~QueryLexer();
	void Set(const String &query_string);
	void Next();
	
	virtual bool IsWord() const = 0;
	bool IsQuote() const;
	bool IsEnd() const;
	
	const String &Value() const { return current; }

	const String &FullString() const { return query; }


protected:
	QueryLexer();
	
	String query;
	String current;
};

//
// query parser
// abstract class
//
// The main public interface consists on Parse()
// which returns a query tree after parsing a query string.
// The subclasses must provide a lexer
//

class QueryParser
{
public:
	virtual ~QueryParser() {}
	
	Query *Parse(const String &query_string);
	const String &Error() const { return error; }

protected:
	QueryParser() {}
	
	virtual Query *ParseExpression() = 0;
	virtual QueryLexer &Token() = 0;
	Query *ParseWord();
	Query *ParseExactWord();
	Query *ParsePhrase();
	void Expected(const String &what);

private:
	String error;
};

//
// query lexer for simple (all/any) queries
// 
class SimpleLexer : public QueryLexer
{
public:
	SimpleLexer() : QueryLexer() {}
	bool IsWord() const { return !IsEnd(); }
};

//
// query parser for simple (all/any word) queries
// abstract class
//
class SimpleQueryParser : public QueryParser
{
public:
	virtual ~SimpleQueryParser() {}
	Query *Parse(const String &query_string);

protected:
	SimpleQueryParser() {}

	virtual OperatorQuery *MakeQuery() = 0;

private:
	Query *ParseExpression();
	Query *ParseTerm();
	QueryLexer &Token() { return token; }

	SimpleLexer token;
};

//
// query parser for 'and' (all words) simple queries
//
class AndQueryParser : public SimpleQueryParser
{
public:
	AndQueryParser();
private:
	OperatorQuery *MakeQuery()
	{
		return new AndQuery;
	}
};

//
// query parser for 'or' (any word) simple queries
//
class OrQueryParser : public SimpleQueryParser
{
public:
	OrQueryParser();

private:
	OperatorQuery *MakeQuery()
	{
		return new OrQuery;
	}
};

//
// query lexer for boolean expressions
// defines terminal symbols "word", and, or, not, near, (, ), /
// 
class BooleanLexer : public QueryLexer
{
public:
	bool IsWord() const;
	bool IsAnd() const;
	bool IsOr() const;
	bool IsNear() const;
	bool IsNot() const;
	bool IsLeftParen() const;
	bool IsRightParen() const;
	bool IsSlash() const;
};

class BooleanQueryParser : public QueryParser
{
public:
	BooleanQueryParser() {}
	~BooleanQueryParser() {}

private:
	Query *ParseExpression();
	Query *ParseAnd();
	Query *ParseNot();
	Query *ParseNear();
	Query *ParseFactor();
	QueryLexer &Token() { return token; }

	BooleanLexer token;
};

class GParser : public QueryParser
{
public:
	GParser() {}
	~GParser() {}

private:
	Query *ParseExpression();
	Query *ParseFactor();
	OperatorQuery *MakeOperatorQuery(const String &op) const;
	QueryLexer &Token() { return token; }

	BooleanLexer token;
};

#endif
