package de.ids_mannheim.korap.query;

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

import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.Spans;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.ToStringUtils;

import de.ids_mannheim.korap.query.spans.RepetitionSpans;

/**
 * SpanRepetitionQuery means that the given SpanQuery must appears multiple
 * times in a sequence. The number of repetition depends on the minimum and the
 * maximum number parameters. <br />
 * <br />
 * 
 * In the example below, SpanRepetitionQuery retrieves {@link RepetitionSpans}
 * consisting of the TermSpans "tt:p/ADJ" that must appear at least once or
 * consecutively two times. What appears after the RepetitionSpans is not
 * considered, so it is possible that it is another "tt:p/ADJ". <br />
 * <br />
 * 
 * <pre>
 * SpanRepetitionQuery sq = new SpanRepetitionQuery(new SpanTermQuery(new Term(
 *         &quot;tokens&quot;, &quot;tt:p/ADJ&quot;)), 1, 2, true);
 * </pre>
 * 
 * For instance, "a large black leather jacket" contains the following matches.
 * 
 * <pre>
 *  [large]
 *  [large black]
 *  [black]
 *  [black leather]
 *  [leather]
 * </pre>
 * 
 * @author margaretha
 * */
public class SpanRepetitionQuery extends SimpleSpanQuery {

    private int min, max;

    /**
     * Constructs a SpanRepetitionQuery for the given {@link SpanQuery}.
     * 
     * @param sq a SpanQuery
     * @param min the minimum number of the required repetition
     * @param max the maximum number of the required repetition
     * @param collectPayloads a boolean flag representing the value
     *        <code>true</code> if payloads are to be collected, otherwise
     *        <code>false</code>.
     */
    public SpanRepetitionQuery(SpanQuery sq, int min, int max,
            boolean collectPayloads) {
        super(sq, collectPayloads);
        this.min = min;
        this.max = max;
    }

    @Override
    public SimpleSpanQuery clone() {
        SpanRepetitionQuery sq = new SpanRepetitionQuery(
                (SpanQuery) this.firstClause.clone(), this.min, this.max,
                this.collectPayloads);
        sq.setBoost(getBoost());
        return sq;
    }

    @Override
    public Spans getSpans(AtomicReaderContext context, Bits acceptDocs,
            Map<Term, TermContext> termContexts) throws IOException {
        return new RepetitionSpans(this, context, acceptDocs, termContexts);
    }

    @Override
    public String toString(String field) {
        StringBuilder sb = new StringBuilder();
        sb.append("spanRepetition(");
        sb.append(firstClause.toString(field));
        sb.append("{");
        sb.append(min);
        sb.append(",");
        sb.append(max);
        sb.append("})");
        sb.append(ToStringUtils.boost(getBoost()));
        return sb.toString();
    }

    /**
     * Returns the minimum number of required repetitions.
     * 
     * @return the minimum number of required repetitions
     */
    public int getMin() {
        return min;
    }

    /**
     * Sets the minimum number of required repetitions.
     * 
     * @param min the minimum number of required repetitions
     */
    public void setMin(int min) {
        this.min = min;
    }

    /**
     * Returns the maximum number of required repetitions.
     * 
     * @return the maximum number of required repetitions
     */
    public int getMax() {
        return max;
    }

    /**
     * Sets the maximum number of required repetitions.
     * 
     * @param max the maximum number of required repetitions
     */
    public void setMax(int max) {
        this.max = max;
    }

}
