package eu.dnetlib.springutils.condbean.parser;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import eu.dnetlib.springutils.condbean.ConditionExpressionParser;
import eu.dnetlib.springutils.condbean.parser.ast.AbstractExpression;
import eu.dnetlib.springutils.condbean.parser.ast.Converter;
import fri.patterns.interpreter.parsergenerator.Lexer;
import fri.patterns.interpreter.parsergenerator.Parser;
import fri.patterns.interpreter.parsergenerator.ParserTables;
import fri.patterns.interpreter.parsergenerator.lexer.LexerException;
import fri.patterns.interpreter.parsergenerator.parsertables.LALRParserTables;
import fri.patterns.interpreter.parsergenerator.parsertables.ParserBuildException;
import fri.patterns.interpreter.parsergenerator.syntax.SyntaxException;
import fri.patterns.interpreter.parsergenerator.syntax.builder.SyntaxBuilder;

public class RunccExpressionParser implements ConditionExpressionParser {

	private static final Log log = LogFactory //NOPMD
			.getLog(RunccExpressionParser.class);

	private Parser parser;
	private InputStream syntaxInput;
	private SyntaxBuilder builder;
	private Lexer lexer;
	private ParserTables tables;
	
	private CondBeanParser condBeanParser;

	@Override
	public boolean expressionValue(final String expression) {
		try {
			parser.setInput(expression);
			if (!parser.parse(condBeanParser))
				log.fatal("Syntax errors in the expression");
		} catch (IOException ioExc) {
			log.fatal("Error in evaluating the expression", ioExc);
		}
		return Converter.toBoolean(((AbstractExpression) parser.getResult()).evaluate());
	}

	public AbstractExpression getTopRule(final String expression) {
		try {
			parser.setInput(expression);
			if (!parser.parse(new CondBeanParser()))
				log.fatal("Syntax errors in the expression");
		} catch (IOException ioExc) {
			log.fatal("Error in evaluating the expression", ioExc);
		}
		return (AbstractExpression) parser.getResult();
	}

	public RunccExpressionParser() {
		try {
			syntaxInput = CondBeanParser.class.getResourceAsStream("CondBeanParser.syntax");
			builder = new SyntaxBuilder(syntaxInput);
			lexer = builder.getLexer();
			tables = new LALRParserTables(builder.getParserSyntax());
			parser = new Parser(tables);
			parser.setLexer(lexer);
		} catch (SyntaxException syntEx) {
			log.fatal("Errors in the syntax specification!", syntEx);
		} catch (LexerException lexEx) {
			log.fatal("Lexer error!", lexEx);
		} catch (ParserBuildException parsBuilEx) {
			log.fatal("Cannot create the Parser, errors in the grammar specification!", parsBuilEx);
		} catch (IOException ioEx) {
			throw new IllegalStateException("Cannot read the grammar file!", ioEx);
		}
	}

	public Parser getParser() {
		return parser;
	}

	public void setParser(final Parser parser) {
		this.parser = parser;
	}

	public InputStream getSyntaxInput() {
		return syntaxInput;
	}

	public void setSyntaxInput(final InputStream syntaxInput) {
		this.syntaxInput = syntaxInput;
	}

	public SyntaxBuilder getBuilder() {
		return builder;
	}

	public void setBuilder(final SyntaxBuilder builder) {
		this.builder = builder;
	}

	public Lexer getLexer() {
		return lexer;
	}

	public void setLexer(final Lexer lexer) {
		this.lexer = lexer;
	}

	public ParserTables getTables() {
		return tables;
	}

	public void setTables(final ParserTables tables) {
		this.tables = tables;
	}

	public CondBeanParser getCondBeanParser() {
		return condBeanParser;
	}

	public void setCondBeanParser(CondBeanParser condBeanParser) {
		this.condBeanParser = condBeanParser;
	}

}
