package com.tyndalehouse.step.core.service.impl.suggestion;
import com.tyndalehouse.step.core.data.EntityDoc;
import com.tyndalehouse.step.core.data.EntityIndexReader;
import com.tyndalehouse.step.core.exceptions.StepInternalException;
import com.tyndalehouse.step.core.models.LexiconSuggestion;
import com.tyndalehouse.step.core.models.search.PopularSuggestion;
import com.tyndalehouse.step.core.service.SingleTypeSuggestionService;
import com.tyndalehouse.step.core.service.helpers.SuggestionContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopFieldCollector;
import javax.swing.text.Highlighter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import static com.tyndalehouse.step.core.service.helpers.OriginalWordUtils.convertToSuggestion;
/**
* @author chrisburrell
*/
public abstract class AbstractAncientSuggestionServiceImpl implements SingleTypeSuggestionService<EntityDoc, TopFieldCollector> {
private final EntityIndexReader reader;
private final Sort popularSort;
private final Sort sort;
private final Filter filter;
protected AbstractAncientSuggestionServiceImpl(EntityIndexReader reader, final Filter filter, final Sort sort, final Sort popularSort) {
this.reader = reader;
this.filter = filter;
this.sort = sort;
this.popularSort = popularSort;
}
@Override
public EntityDoc[] getExactTerms(SuggestionContext context, final int max, final boolean popularSort) {
return context.getInput().indexOf(' ') != -1 ? new EntityDoc[0] : getTerms(context.getInput(), max, true, popularSort);
}
@Override
public EntityDoc[] collectNonExactMatches(final TopFieldCollector collector, final SuggestionContext context, final EntityDoc[] alreadyRetrieved,
final int leftToCollect) {
if(context.getInput().indexOf(' ') != -1) {
return new EntityDoc[0];
}
final BooleanQuery query = this.getQuery(context.getInput(), false);
if (alreadyRetrieved != null) {
for (EntityDoc doc : alreadyRetrieved) {
//make sure we don't retrieve docs that have already been retrieved
query.add(new TermQuery(new Term("strongNumber", doc.get("strongNumber"))), BooleanClause.Occur.MUST_NOT);
}
}
final EntityDoc[] search = this.reader.search(query, this.filter, collector);
//we're interested in the results if we wanted more, or if we're retrieving a single result (cos we don't want to display grouping)
if (leftToCollect > 0 || collector.getTotalHits() == 1) {
return search;
}
//not really interested, just interested in the count
return new EntityDoc[0];
}
@Override
public List<? extends PopularSuggestion> convertToSuggestions(
final EntityDoc[] docs,
final EntityDoc[] extraDocs) {
final List<LexiconSuggestion> suggestions = this.convertDefinitionDocsToSuggestion(docs);
suggestions.addAll(this.convertDefinitionDocsToSuggestion(extraDocs));
return suggestions;
}
private EntityDoc[] getTerms(final String form, final int max, boolean exact, final boolean popularSort) {
final BooleanQuery masterQuery = getQuery(form, exact);
return this.reader.search(masterQuery, max, getSort(popularSort), this.filter);
}
protected Query getExactOrPrefixQuery(final boolean exact, final Term stepGlossTerm) {
return exact ? new TermQuery(stepGlossTerm) : new PrefixQuery(stepGlossTerm);
}
/**
* Takes EntityDocs representing Definition entities and converts them to a suggestion
*
* @param results the results
* @return true
*/
private List<LexiconSuggestion> convertDefinitionDocsToSuggestion(final EntityDoc[] results) {
final List<LexiconSuggestion> suggestions = new ArrayList<LexiconSuggestion>();
if (results != null) {
for (final EntityDoc def : results) {
suggestions.add(convertToSuggestion(def));
}
}
return suggestions;
}
protected abstract BooleanQuery getQuery(String form, boolean exact);
protected Sort getSort(boolean popular) {
return popular ? this.popularSort : this.sort;
}
@Override
public TopFieldCollector getNewCollector(final int leftToCollect, final boolean popularSort) {
try {
return TopFieldCollector.create(getSort(popularSort), leftToCollect > 0 ? leftToCollect : 1, false, false, false, false);
} catch (IOException ex) {
throw new StepInternalException(ex.getMessage(), ex);
}
}
/**
* @return the reader associated with this suggestion service
*/
protected EntityIndexReader getReader() {
return this.reader;
}
}