package eu.dnetlib.data.collective.transformation.rulelanguage;

import java.io.InputStream;
import java.io.Reader;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTStart;
import eu.dnetlib.data.collective.transformation.rulelanguage.parser.FtScript;
import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ParseException;
import eu.dnetlib.data.collective.transformation.rulelanguage.parser.SimpleNode;
import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyScript.SCRIPTTYPE;
import eu.dnetlib.data.collective.transformation.rulelanguage.util.FunctionCall;
import eu.dnetlib.data.collective.transformation.rulelanguage.visitor.AbstractVisitor;
import eu.dnetlib.data.collective.transformation.rulelanguage.visitor.RuleLanguageVisitor;

/**
 * Parser for rule scripts
 * @author jochen
 *
 */
public class RuleLanguageParser {

	private static final Log log = LogFactory.getLog(RuleLanguageParser.class);
	private RuleLanguageVisitor visitor = new RuleLanguageVisitor();
	protected static FtScript scriptParser = null;
	private String xslStylesheet = null;
	
	public void parse(InputStream inStream){
		
		if (scriptParser == null) scriptParser = new FtScript(inStream);
		scriptParser.ReInit(inStream);
		parsingAndTraversing();
	}
	
	public void parse(Reader inRead){
		if (scriptParser == null) scriptParser = new FtScript(inRead);
		scriptParser.ReInit(inRead);		
		parsingAndTraversing();
	}
	
	private void parsingAndTraversing(){
		try {
			ASTStart start = scriptParser.Start();
			traverseTree(start, visitor);
		} catch (ParseException e) {
			log.error(e);
			throw new IllegalStateException(e);
		}
	}
	
	public String getScriptName(){
		return visitor.getScriptName();
	}
	
	public SCRIPTTYPE getScriptType(){
		return visitor.getScriptType();
	}
	
	public Map<String, Set<IRule>> getElementMappingRules(){
		return visitor.getElementMappingRules();
	}
	
	public Map<String, IRule> getVariableMappingRules(){
		return visitor.getVariableMappingRules();
	}
	
	public Map<String, IRule> getTemplateMappingRules(){
		return visitor.getTemplateMappingRules();
	}
	
	public List<String> getImportedScripts(){
		return visitor.getImportedScripts();
	}
	
	public Map<String, String> getNamespaceDeclarations(){
		return visitor.getNamespaceDeclarations();
	}
	
	public List<FunctionCall> getFunctionCalls(){
		return visitor.getFunctionCalls();
	}
	
	public List<Map<String, String>> getPreprocessings(){
		return visitor.getPreprocessings();
	}
	
	public String getXslStylesheet() {
		return xslStylesheet;
	}

	public void setXslStylesheet(String xslStylesheet) {
		this.xslStylesheet = xslStylesheet;
	}
	
	public boolean isXslStylesheet(){
		if (xslStylesheet != null) return true;
		else return false;
	}

	/**
	 * adds the rules and name-space declarations from another parser, e.g. a child parser of imported scripts, to this parser
	 * @param aParser
	 */
	public void addRulesFromParser(RuleLanguageParser aParser){
		this.visitor.getFunctionCalls().addAll(aParser.getFunctionCalls());
		this.visitor.getElementMappingRules().putAll(aParser.getVisitor().getElementMappingRules());
		this.visitor.getVariableMappingRules().putAll(aParser.getVisitor().getVariableMappingRules());
		this.visitor.getTemplateMappingRules().putAll(aParser.getVisitor().getTemplateMappingRules());
		this.visitor.getNamespaceDeclarations().putAll(aParser.getNamespaceDeclarations());
	}
	
	protected RuleLanguageVisitor getVisitor(){
		return visitor;
	}
	
	private void traverseTree(SimpleNode node, AbstractVisitor visitor){
		for (int i = 0; i < node.jjtGetNumChildren(); i++){
			SimpleNode sn = (SimpleNode)node.jjtGetChild(i);
			sn.jjtAccept(visitor, null);
			traverseTree(sn, visitor);
		}
	}
	
}
