package eu.dnetlib.functionality.index.query;

import java.util.Collection;
import java.util.List;

import com.google.common.collect.BiMap;
import com.google.common.collect.Iterables;

import eu.dnetlib.data.provision.index.rmi.BrowsingRow;
import eu.dnetlib.functionality.index.model.document.IndexDocument;
import eu.dnetlib.functionality.index.utils.IndexFieldUtility;
import eu.dnetlib.miscutils.functional.UnaryFunction;

/**
 * The Class QueryResponseParser.
 */
public abstract class QueryResponseParser {

	/** The highlight utils. */
	protected final UnaryFunction<String, String> highlightUtils;

	/** The aliases. */
	protected final BiMap<String, String> aliases;

	/** The return empty fields. */
	protected final boolean returnEmptyFields;

	/** The include ranking. */
	protected final boolean includeRanking;

	/** The wrapper rank. */
	protected final UnaryFunction<String, IndexDocument> wrapperRank = new UnaryFunction<String, IndexDocument>() {

		@Override
		public String evaluate(final IndexDocument doc) {
			return addRanking(getSingleField(doc, IndexFieldUtility.RESULT), getSingleField(doc, IndexFieldUtility.SCORE_FIELD));
		}
	};

	/** The wrapper no rank. */
	protected final UnaryFunction<String, IndexDocument> wrapperNoRank = new UnaryFunction<String, IndexDocument>() {

		@Override
		public String evaluate(final IndexDocument doc) {
			return wrap(getSingleField(doc, IndexFieldUtility.RESULT));
		}
	};

	/**
	 * Gets the single field.
	 *
	 * @param doc
	 *            the doc
	 * @param fieldName
	 *            the field name
	 * @return the single field
	 */
	@SuppressWarnings("unchecked")
	private String getSingleField(final IndexDocument doc, final String fieldName) {
		Object value = doc.getFieldValue(fieldName);
		if (value instanceof Collection) return Iterables.getOnlyElement((Iterable<String>) value);
		return String.valueOf(value);
	}

	/**
	 * Instantiates a new query response parser.
	 *
	 * @param queryRsp
	 *            the query rsp
	 * @param highlightUtils
	 *            the highlight utils
	 * @param aliases
	 *            the aliases
	 * @param returnEmptyFields
	 *            the return empty fields
	 * @param includeRanking
	 *            the include ranking
	 */
	public QueryResponseParser(final UnaryFunction<String, String> highlightUtils, final BiMap<String, String> aliases, final boolean returnEmptyFields,
			final boolean includeRanking) {

		this.highlightUtils = highlightUtils;
		this.aliases = aliases;
		this.returnEmptyFields = returnEmptyFields;
		this.includeRanking = includeRanking;
	}

	/**
	 * Converts a String document to
	 *
	 * <record rank="score"> [document] </record>.
	 *
	 * @param doc
	 *            the doc
	 * @param score
	 *            the score
	 * @return the string
	 */
	private String addRanking(final String doc, final String score) {
		return new String("<record rank=\"" + score + "\">" + doc + "</record>");
	}

	/**
	 * Wraps the given document as <record> [document] </record>.
	 *
	 * @param doc
	 *            the doc
	 * @return the string
	 */
	private String wrap(final String doc) {
		return new String("<record>" + doc + "</record>");
	}

	/**
	 * Gets the num found.
	 *
	 * @return the num found
	 */
	public abstract long getNumFound();

	/**
	 * Gets the query time.
	 *
	 * @return the query time
	 */
	public abstract int getQueryTime();

	/**
	 * Gets the elapsed time.
	 *
	 * @return the elapsed time
	 */
	public abstract long getElapsedTime();

	/**
	 * Gets the status.
	 *
	 * @return the status
	 */
	public abstract String getStatus();

	/**
	 * Gets the start.
	 *
	 * @return the start
	 */
	public abstract long getStart();

	/**
	 * Gets the current size.
	 *
	 * @return the current number of documents.
	 */
	public abstract int getCurrentSize();

	/**
	 * Gets the results.
	 *
	 * @return query results as a List<String>
	 */
	public abstract List<String> getResults();

	/**
	 * method counts the number of facet fields resulting from the performed query.
	 *
	 * @return the number of browsing results
	 */
	public abstract Long getNumberOfBrowsingResults();

	/**
	 * Gets the browsing results.
	 *
	 * @return the browsing results
	 */
	public abstract List<BrowsingRow> getBrowsingResults();

	public BiMap<String, String> getAliases() {
		return aliases;
	}

}
