package cz.brmlab.yodaqa.pipeline;

import java.util.Iterator;

import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.uima.UimaContext;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.AbstractCas;
import org.apache.uima.fit.component.JCasMultiplier_ImplBase;
import org.apache.uima.fit.descriptor.ConfigurationParameter;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.util.CasCopier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.brmlab.yodaqa.model.Question.Clue;
import cz.brmlab.yodaqa.model.SearchResult.ResultInfo;
import cz.brmlab.yodaqa.provider.Solr;

import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token;

/**
 * Take a question CAS and search for keywords, yielding a search result
 * CAS instance.
 *
 * We just feed all the clues to a Solr search. */

public class PrimarySearch extends JCasMultiplier_ImplBase {
	final Logger logger = LoggerFactory.getLogger(PrimarySearch.class);

	/** Number of results to grab and analyze. */
	public static final String PARAM_HITLIST_SIZE = "hitlist-size";
	@ConfigurationParameter(name = PARAM_HITLIST_SIZE, mandatory = false, defaultValue = "6")
	private int hitListSize;

	/** Whether embedded (internal) or standalone (external) Solr
	 * instance is to be used. */
	public static final String PARAM_EMBEDDED = "embedded";
	@ConfigurationParameter(name = PARAM_EMBEDDED, mandatory = false, defaultValue = "true")
	protected boolean embedded;

	/** "Core" is the name of Solr database. In case of embedded,
	 * the pathname to one. */
	public static final String PARAM_CORE = "core";
	@ConfigurationParameter(name = PARAM_CORE, mandatory = false, defaultValue = "data/guten")
	protected String core;

	/** URL to a Solr server if !embedded. */
	public static final String PARAM_SERVER_URL = "server-url";
	@ConfigurationParameter(name = PARAM_SERVER_URL, mandatory = false, defaultValue = "http://localhost:8983/solr/")
	protected String serverUrl;

	protected Solr solr;

	JCas src_jcas;
	protected Iterator<SolrDocument> documenti;
	int i;

	public void initialize(UimaContext aContext) throws ResourceInitializationException {
		super.initialize(aContext);

		try {
			this.solr = new Solr(serverUrl, null, embedded, core);
		} catch (Exception e) {
			throw new ResourceInitializationException(e);
		}
	}

	@Override
	public void process(JCas jcas) throws AnalysisEngineProcessException {
		src_jcas = jcas;
		i = 0;

		String query = formulateQuery(jcas);
		try {
			SolrDocumentList documents = solr.runQuery(query, hitListSize);
			documenti = documents.iterator();
		} catch (Exception e) {
			throw new AnalysisEngineProcessException(e);
		}
	}

	@Override
	public boolean hasNext() throws AnalysisEngineProcessException {
		return documenti.hasNext();
	}

	@Override
	public AbstractCas next() throws AnalysisEngineProcessException {
		JCas jcas = getEmptyJCas();
		try {
			jcas.createView("Question");
			CasCopier copier = new CasCopier(src_jcas.getCas(), jcas.getCas());
			copyQuestion(copier, src_jcas, jcas.getView("Question"));

			jcas.createView("Result");
			generateResult(documenti.next(), jcas.getView("Result"), !documenti.hasNext());
		} catch (Exception e) {
			jcas.release();
			throw new AnalysisEngineProcessException(e);
		}
		i++;
		return jcas;
	}

	@Override
	public void collectionProcessComplete() throws AnalysisEngineProcessException {
		super.collectionProcessComplete();
		solr.close();
	}


	protected String formulateQuery(JCas jcas) {
		StringBuffer result = new StringBuffer();
		for (Clue clue : JCasUtil.select(jcas, Clue.class)) {
			if (!(clue.getBase() instanceof Token))
				continue;
			if (result.length() > 0)
				result.append("AND ");
			String keyterm = clue.getCoveredText();
			result.append("(\"" + keyterm + "\" OR titleText:\"" + keyterm + "\") ");
		}
		String query = result.toString();
		logger.info(" QUERY: " + query);
		return query;
	}

	protected void copyQuestion(CasCopier copier, JCas src, JCas jcas) throws Exception {
		copier.copyCasView(src.getCas(), jcas.getCas(), true);
	}

	protected void generateResult(SolrDocument document, JCas jcas,
			boolean isLast) throws Exception {

		Integer id = (Integer) document.getFieldValue("id");
		String title = (String) document.getFieldValue("titleText");
		logger.info(" FOUND: " + id + " " + (title != null ? title : ""));
		String text;
		try {
			text = solr.getDocText(id.toString());
		} catch (SolrServerException e) {
			e.printStackTrace();
			return;
		}
		// System.err.println("--8<-- " + text + " --8<--");
		jcas.setDocumentText(text);
		jcas.setDocumentLanguage("en"); // XXX

		ResultInfo ri = new ResultInfo(jcas);
		ri.setDocumentId(id.toString());
		ri.setDocumentTitle(title);
		ri.setRelevance(((Float) document.getFieldValue("score")).floatValue());
		ri.setIsLast(isLast);
		ri.addToIndexes();
	}
}

@@ -901,30 +901,42 @@
 pi.s
-egmentation.type.Token
+yntax.type.constituent.Constituent
 ;%0A%0A/
@@ -3857,13 +3857,78 @@
 %0A%09%09%09
+// constituent clues are too phrasal for use as search keywords%0A%09%09%09
 if 
-(!
 (clu
@@ -3954,14 +3954,19 @@
 eof 
-Token)
+Constituent
 )%0A%09%09

Include all non-constituent clues