Preliminary support for korap:focus and operation:repetition deserialization
diff --git a/CHANGES b/CHANGES
index f39b7d0..b54d356 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+0.31.6 2014-06-30
+        - [feature] support for korap:reference deserialization (diewald)
+	- [feature] Preliminary support for attributes in elements (margaretha)
+	- [feature] Preliminary support operation:repetition deserialization
+	  (unfinished and untested; diewald)
+
 0.31.5 2014-06-17
         - [feature] Batch return of defined foundries and layers in
 	  getMatchInfo() (diewald)
diff --git a/pom.xml b/pom.xml
index 7006850..ec7be9c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
 -->
   <groupId>KorAP-modules</groupId>
   <artifactId>KorAP-lucene-index</artifactId>
-  <version>0.31.5</version>
+  <version>0.31.6</version>
   <packaging>jar</packaging>
 
   <name>KorAP-lucene-index</name>
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index 5944f29..1485f5d 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -189,26 +189,6 @@
 		    this.fromJSON(operands.get(0)), number
                 );
 
-	    case "operation:focus":
-		number = 0;
-
-		if (operands.size() != 1)
-		    throw new QueryException("Operation needs exactly two operands");
-
-		if (json.has("classRef")) {
-		    if (json.has("classRefOp"))
-			throw new QueryException("Class reference operators not supported yet");
-
-		    number = json.get("classRef").get(0).asInt();
-		}
-		else if (json.has("spanRef")) {
-		    throw new QueryException("Span references not supported yet");
-		};
-
-		return new SpanMatchModifyQueryWrapper(
-		    this.fromJSON(operands.get(0)), number
-                );
-
 	    case "operation:sequence":
 		if (operands.size() < 2)
 		    throw new QueryException(
@@ -278,16 +258,67 @@
 		throw new QueryException("Class group expects class attribute");
 
 	    case "operation:repetition":
-		throw new QueryException("Repetition group not yet supported");
 
-		/*
-		  if (json.has("min") || json.has("max"))
-		  throw new QueryException("Quantifier for repetition group not yet supported");
-		*/
+		// temporary
+		int min = json.get("min").asInt(1);
+		int max = json.get("max").asInt(1);
+
+		// Sanitize max
+		if (max < 0)
+		    max = 100;
+		else if (max > 100)
+		    max = 100;
+
+		// Sanitize min
+		if (min < 0)
+		    min = 0;
+		else if (min > 100)
+		    max = 100;
+
+		// Check relation between min and max
+		if (min > max)
+		    throw new QueryException("The maximum repetition value has to " +
+					     "be greater or equal to the minimum repetition value");
+
+		if (min == 0)
+		    throw new QueryException("Minimum value of zero is not supported yet");
+
+		return new SpanRepetitionQueryWrapper(
+		    this.fromJSON(operands.get(0)), min, max
+		);
 	    };
 
 	    throw new QueryException("Unknown group operation");
 
+	case "korap:reference":
+	    if (json.has("operation") && json.get("operation").asText() != "operation:focus")
+		throw new QueryException("Reference operation not supported yet");
+
+	    int number = 0;
+
+	    operands = json.get("operands");
+
+	    if (operands.size() == 0)
+		throw new QueryException("Focus with peripheral references is not supported yet");
+
+	    if (operands.size() != 1)
+		throw new QueryException("Operation needs exactly two operands");
+
+
+	    if (json.has("classRef")) {
+		if (json.has("classRefOp"))
+		    throw new QueryException("Class reference operators not supported yet");
+
+		number = json.get("classRef").get(0).asInt();
+	    }
+	    else if (json.has("spanRef")) {
+		throw new QueryException("Span references not supported yet");
+	    };
+
+	    return new SpanMatchModifyQueryWrapper(
+	        this.fromJSON(operands.get(0)), number
+	    );
+
 	case "korap:token":
 	    if (!json.has("wrap"))
 		throw new QueryException("Tokens need a wrap attribute");
@@ -681,6 +712,16 @@
 	return new SpanMatchModifyQueryWrapper(element);
     };
 
+    // Repetition
+    public SpanRepetitionQueryWrapper repeat (SpanQueryWrapperInterface element, int exact) {
+	return new SpanRepetitionQueryWrapper(element, exact);
+    };
+
+    public SpanRepetitionQueryWrapper repeat (SpanQueryWrapperInterface element, int min, int max) {
+	return new SpanRepetitionQueryWrapper(element, min, max);
+    };
+
+
     // split
 
 };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapperInterface.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapperInterface.java
index a4b1fcb..035e867 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapperInterface.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapperInterface.java
@@ -4,6 +4,8 @@
 
 // Todo: Make this an abstract class to deal with regexes in a parent abstract class!
 
+// Add optional and null attributes
+
 public interface SpanQueryWrapperInterface {
     public SpanQuery toQuery ();
 };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
new file mode 100644
index 0000000..8ab2937
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
@@ -0,0 +1,29 @@
+package de.ids_mannheim.korap.query.wrap;
+
+import org.apache.lucene.search.spans.SpanQuery;
+
+import de.ids_mannheim.korap.query.SpanRepetitionQuery;
+import de.ids_mannheim.korap.query.wrap.SpanQueryWrapperInterface;
+
+
+public class SpanRepetitionQueryWrapper implements SpanQueryWrapperInterface {
+    private SpanQueryWrapperInterface subquery;
+    private int min = 1;
+    private int max = 1;
+
+    public SpanRepetitionQueryWrapper (SpanQueryWrapperInterface subquery, int exact) {
+	this.subquery = subquery;
+	this.min = exact;
+	this.max = exact;
+    };
+
+    public SpanRepetitionQueryWrapper (SpanQueryWrapperInterface subquery, int min, int max) {
+	this.subquery = subquery;
+	this.min = min;
+	this.max = max;
+    };
+
+    public SpanQuery toQuery () {
+	return new SpanRepetitionQuery(this.subquery.toQuery(), this.min, this.max, true);
+    };
+};