package eu.dnetlib.dlms.jdbc.server;

import java.sql.SQLException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import eu.dnetlib.dlms.jdbc.ast.Statement;
import eu.dnetlib.dlms.jdbc.parser.IDQLParser;

/**
 * Engine for the execution of DOL strings.
 * 
 * @author alessia
 * 
 */
public class DOLEngine extends AbstractDOLEngine {
	/** Logger. */
	private static final Log log = LogFactory.getLog(DOLEngine.class);

	/**
	 * Replace ? placholders with ordered param. Index numbers start from 1.
	 * 
	 * @param dolString
	 *            Original dol string
	 * @return a new string which is dolString whose ? are replaced by ?index
	 */
	protected String replaceWithIndexedParam(final String dolString) {
		//matches '?' not precceeded by a '\' and not followed by a digit (from 0 to 9)
		Pattern p = Pattern.compile("(?<!\\\\)\\?(?!\\d)");
		Matcher m = p.matcher(dolString);
		StringBuffer sb = new StringBuffer();
		int count = 1;
		while (m.find()) {
			m.appendReplacement(sb, "?" + count + "");
			count++;
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.server.AbstractDOLEngine#execute(java.lang.String, java.util.Map)
	 */
	@Override
	public AbstractDOLExecuter execute(final String dolString, final Map<String, ParamInfo> params) throws SQLException {
		log.debug(this + ".execute(" + dolString + ", " + params + ")");
		String toParse = replaceWithIndexedParam(dolString);
		toParse = toParse.replaceAll("@", "attribute::");
		IDQLParser dolParser = getParserFactory().createParser();
		final Collection<Statement> parsedStms = dolParser.parse(toParse);
		log.info("AST: " + parsedStms);
		final AbstractDOLExecuter executer = getExecuterFactory().createExecuter();
		try {
			executer.execute(parsedStms, params);
		} catch (ExecutionException e) {
			throw new SQLException(e);
		}
		return executer;
	}
}
