package net.sf.okapi.lib.search.lucene.query;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import net.sf.okapi.common.resource.TextFragment;
import net.sf.okapi.lib.search.lucene.scorer.SimpleConcordanceFuzzyScorer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;

/**
 * A concordance query which only accepts strings instead of {@link TextFragment}s. Phrase positions inside the TM
 * source or target segments are not generated by this query.
 * 
 * @author HARGRAVEJE
 * 
 */
@SuppressWarnings("serial")
public class SimpleConcordanceFuzzyQuery extends Query {
	float threshold;
	List<Term> terms;

	/**
	 * Construct a SimpleConcordanceFuzzyQuery specifying the fuzzy threshold.
	 * 
	 * @param threshold
	 *            - value between 0.0 and 1.0, where 1.0 is a perfect match and 0.0 is no match.
	 */
	public SimpleConcordanceFuzzyQuery(float threshold) {
		this.threshold = threshold;
		terms = new LinkedList<Term>();
	}

	/**
	 * Add a search {@link Term} to the query.
	 * 
	 * @param term - {@link Term} generated by a Lucene {@link Analyzer}
	 */
	public void add(Term term) {
		terms.add(term);
	}

	@Override
	public Weight createWeight(Searcher searcher) throws IOException {
		return new SimpleConcordanceFuzzyWeight(searcher);
	}

	@Override
	@SuppressWarnings("unchecked")
	public void extractTerms(Set terms) {
		terms.add(terms);
	}

	@Override
	public Query rewrite(IndexReader reader) throws IOException {
		return this;
	}

	@Override
	public String toString(String field) {
		return terms.toString();
	}

	protected class SimpleConcordanceFuzzyWeight extends Weight {
		Similarity similarity;

		public SimpleConcordanceFuzzyWeight(Searcher searcher) throws IOException {
			super();
			this.similarity = searcher.getSimilarity();
		}

		@Override
		public Explanation explain(IndexReader reader, int doc) throws IOException {
			return new Explanation(getValue(), toString());
		}

		@Override
		public Query getQuery() {
			return SimpleConcordanceFuzzyQuery.this;
		}

		@Override
		public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer)
				throws IOException {
			// optimize zero-term or no match case
			if (terms.size() == 0)
				return null;
			return new SimpleConcordanceFuzzyScorer(threshold, similarity, terms, reader);
		}

		@Override
		public float getValue() {
			return 1.0f;
		}

		@Override
		public void normalize(float norm) {
		}

		@Override
		public float sumOfSquaredWeights() throws IOException {
			return 1.0f;
		}
	}
}
