package eu.dnetlib.functionality.cql;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import eu.dnetlib.functionality.cql.lucene.IdentityCqlValueTransformerMap;
import eu.dnetlib.functionality.cql.lucene.LuceneCqlTranslator;
import eu.dnetlib.functionality.cql.lucene.TranslatedQuery;
import eu.dnetlib.functionality.cql.mongo.MongoCqlTranslator;
import org.bson.conversions.Bson;
import org.z3950.zing.cql.CQLNode;
import org.z3950.zing.cql.CQLParseException;
import org.z3950.zing.cql.CQLParser;

/**
 * This class provides a simple cql-to-lucene translator
 * 
 * TODO implement translation distinguishing org.apache.lucene.search.TermRangeQuery and
 * org.apache.lucene.search.NumericRangeQuery
 * 
 * @author claudio
 * 
 */
public class CqlTranslatorImpl implements CqlTranslator {

	/**
	 * {@link CqlTranslator#toLucene(String)}
	 */
	@Override
	public String toLucene(final String queryRoot) throws CQLParseException, IOException {
		return toLucene(parse(queryRoot), new IdentityCqlValueTransformerMap());
	}

	@Override
	public String toLucene(final String queryRoot, Map<String, List<String>> options) throws CQLParseException, IOException {
		return toLucene(parse(queryRoot), new IdentityCqlValueTransformerMap(), options);
	}

	@Override
	public String toLucene(final String queryRoot, CqlValueTransformerMap valueTransformerMap) throws CQLParseException, IOException {
		return toLucene(parse(queryRoot), valueTransformerMap);
	}

	@Override
	public String toLucene(final CQLNode queryRoot) throws CQLParseException, IOException {
		return toLucene(queryRoot, new IdentityCqlValueTransformerMap());
	}

	@Override
	public String toLucene(final CQLNode queryRoot, CqlValueTransformerMap valueTransformerMap) throws CQLParseException, IOException {

		return getTranslatedQuery(queryRoot, valueTransformerMap).asLucene();
	}

	@Override
	public String toLucene(final CQLNode queryRoot, CqlValueTransformerMap valueTransformerMap, Map<String, List<String>> options)
			throws CQLParseException, IOException {
		final BiMap<String, String> aliases = HashBiMap.create();
		return getTranslatedQuery(queryRoot, valueTransformerMap, options, aliases, new HashMap<String, String>()).asLucene();
	}

	@Override
	public TranslatedQuery getTranslatedQuery(final CQLNode queryRoot, CqlValueTransformerMap valueTransformerMap) throws CQLParseException, IOException {

		final BiMap<String, String> aliases = HashBiMap.create();
		return getTranslatedQuery(queryRoot, valueTransformerMap, new HashMap<String, List<String>>(), aliases, new HashMap<String, String>());
	}

	@Override
	public TranslatedQuery getTranslatedQuery(
			final CQLNode queryRoot,
			CqlValueTransformerMap valueTransformerMap,
			Map<String, List<String>> options,
			BiMap<String, String> aliases,
			Map<String, String> weights) throws CQLParseException, IOException {

		return LuceneCqlTranslator.translate(hackAnd(queryRoot), valueTransformerMap, options, aliases, weights);
	}

	// hack, to be removed soon
	private CQLNode hackAnd(final CQLNode queryRoot) throws CQLParseException, IOException {
		String cql = queryRoot.toCQL().toLowerCase();

		if (cql.startsWith("\"and ") || cql.startsWith("and ")) {
			return parse(cql.replaceFirst("and ", ""));
		}
		return queryRoot;
	}

	@Override
	public TranslatedQuery getTranslatedQuery(String cqlQuery) throws CQLParseException, IOException {
		return getTranslatedQuery(parse(cqlQuery), new IdentityCqlValueTransformerMap());
	}

	@Override
	public TranslatedQuery getTranslatedQuery(String cqlQuery, Map<String, List<String>> options) throws CQLParseException, IOException {
		final BiMap<String, String> aliases = HashBiMap.create();
		return getTranslatedQuery(parse(cqlQuery), new IdentityCqlValueTransformerMap(), options, aliases, new HashMap<String, String>());
	}

	@Override
	public TranslatedQuery getTranslatedQuery(String cqlQuery, CqlValueTransformerMap valueTransformerMap) throws CQLParseException, IOException {
		return getTranslatedQuery(parse(cqlQuery), valueTransformerMap);
	}

	@Override
	public TranslatedQuery getTranslatedQuery(String cqlQuery, CqlValueTransformerMap valueTransformerMap, Map<String, List<String>> options)
			throws CQLParseException, IOException {
		final BiMap<String, String> aliases = HashBiMap.create();
		return getTranslatedQuery(parse(cqlQuery), valueTransformerMap, options, aliases, new HashMap<String, String>());
	}

	@Override
	public Bson toMongo(final String cqlQuery) throws IOException, CQLParseException {
		return MongoCqlTranslator.toMongo(cqlQuery);
	}

	/**
	 * helper parsing method
	 * 
	 * @param query
	 * @return
	 * @throws CQLParseException
	 * @throws IOException
	 */
	protected static CQLNode parse(final String query) throws CQLParseException, IOException {
		return new CQLParser().parse(query);
	}



}
