Added SpanExpansionQuery
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/ExpandedSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/ExpandedSpans.java
new file mode 100644
index 0000000..29c2d14
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/ExpandedSpans.java
@@ -0,0 +1,114 @@
+package de.ids_mannheim.korap.query.spans;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+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.util.Bits;
+
+import de.ids_mannheim.korap.query.SpanExpansionQuery;
+
+public class ExpandedSpans extends SimpleSpans{
+	
+	private int min, max;
+	private boolean isBefore;	
+	private List<CandidateSpan> candidateSpans;
+	private long matchCost;
+	
+	public ExpandedSpans(SpanExpansionQuery spanExpansionQuery,
+			AtomicReaderContext context, Bits acceptDocs,
+			Map<Term, TermContext> termContexts) throws IOException {
+		super(spanExpansionQuery, context, acceptDocs, termContexts);
+		this.min = spanExpansionQuery.getMin();
+		this.max = spanExpansionQuery.getMax();
+		this.isBefore = spanExpansionQuery.isBefore();
+		
+		candidateSpans = new ArrayList<CandidateSpan>();		
+		hasMoreSpans = true;		
+	}
+
+	@Override
+	public boolean next() throws IOException {
+		matchPayload.clear();
+		isStartEnumeration = false;
+		return advance();
+	}
+
+	private boolean advance() throws IOException {		
+		while (hasMoreSpans || candidateSpans.size() > 0) {
+			if (candidateSpans.size() > 0 ){
+				setMatch(candidateSpans.get(0));
+				candidateSpans.remove(0);
+				return true;
+			}
+			else {
+				hasMoreSpans = firstSpans.next();
+				setCandidateList();
+			}
+		}		
+		return false;
+	}
+	
+	private void setCandidateList() throws IOException {
+		CandidateSpan cs;
+		int counter;
+		if (isBefore){
+			counter = max;
+			while (counter >= min ){
+				cs = new CandidateSpan(
+						firstSpans.start() - counter, 
+						firstSpans.end(), 
+						firstSpans.doc(), 
+						firstSpans.cost(), 
+						firstSpans.getPayload()
+				);
+				candidateSpans.add(cs);
+				counter--;
+			}
+		}
+		else{
+			counter = min;
+			while (counter <= max){
+				cs = new CandidateSpan(
+						firstSpans.start(), 
+						firstSpans.end() + counter, 
+						firstSpans.doc(), 
+						firstSpans.cost(), 
+						firstSpans.getPayload()
+				);
+				candidateSpans.add(cs);
+				counter++;
+			}
+		}	
+	}
+
+	private void setMatch(CandidateSpan candidateSpan) {
+		matchDocNumber = candidateSpan.getDoc();
+		matchStartPosition = candidateSpan.getStart();
+		matchEndPosition = candidateSpan.getEnd();			
+		matchPayload = candidateSpan.getPayloads();
+		matchCost = candidateSpan.getCost();
+	}
+
+	@Override
+	public boolean skipTo(int target) throws IOException {
+		if (hasMoreSpans && (firstSpans.doc() < target)){
+  			if (!firstSpans.skipTo(target)){
+  				hasMoreSpans = false;
+  				return false;
+  			}
+  		} 		
+  		matchPayload.clear();
+  		return advance();
+	}
+
+	@Override
+	public long cost() {
+		return matchCost;
+	}
+
+}