Fixed query deserialization for sequences with multiple non-anchors
diff --git a/src/main/java/de/ids_mannheim/korap/KorapIndex.java b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
index a649c35..7278877 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapIndex.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
@@ -1,5 +1,7 @@
 package de.ids_mannheim.korap;
 
+// Todo: ADD WORD COUNT AS A METADATA FIELD!
+
 // Java classes
 import java.util.*;
 import java.util.zip.GZIPInputStream;
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index b49e2f6..a34c46f 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -97,7 +97,7 @@
 		this.max = defaultMax;
 
 	    if (DEBUG)
-		log.trace("Found korap:boundary with {}:{}");
+		log.trace("Found korap:boundary with {}:{}", min, max);
 	};
     };
 
@@ -245,11 +245,10 @@
 
 	    case "operation:sequence":
 
-		if (operands.size() < 2)
-		    throw new QueryException(
-		        612,
-			"SpanSequenceQuery needs at least two operands"
-		    );
+		if (operands.size() == 1) {
+		    this.addWarning("Sequences with less than two operands are ignored");
+		    return this.fromJSON(operands.get(0));
+		};
 
 		SpanSequenceQueryWrapper sseqqw = this.seq();
 
@@ -292,6 +291,7 @@
 		    // Support cosmas distances
 		    else if (firstDistance.get("@type").asText().equals("cosmas:distance"))
 			distances = json.get("distances");
+
 		    else
 			throw new QueryException(612, "No valid distances defined");
 
@@ -308,8 +308,6 @@
                             );
 			*/
 
-
-
 			int min = 0, max = 100;
 			if (constraint.has("boundary")) {
 			    Boundary b = new Boundary(constraint.get("boundary"), 0,100);
@@ -341,6 +339,9 @@
 			if (max < min)
 			    max = min;
 
+			if (DEBUG)
+			    log.trace("Add distance constraint of '{}': {}-{}", unit, min, max);
+
 			sseqqw.withConstraint(min, max, unit);
 		    };
 		};
@@ -350,7 +351,7 @@
 		    sseqqw.append(this.fromJSON(operand));
 		};
 
-		// inOrder was set without a distance constraint
+		// inOrder was set to false without a distance constraint
 		if (!sseqqw.isInOrder() && !sseqqw.hasConstraints()) {
 		    sseqqw.withConstraint(1,1,"w");
 		};
@@ -358,9 +359,8 @@
 		return sseqqw;
 
 	    case "operation:class":
-		number = 0;
+		number = 1;
 
-		
 		if (json.has("classOut")) {
 		    number = json.get("classOut").asInt(0);
 		}
@@ -370,7 +370,12 @@
 		};
 
 		if (json.has("classRefCheck"))
-		    this.addWarning("classRefCheck is not yet supported. Results may not be correct");
+		    this.addWarning("classRefCheck is not yet supported - " +
+				    "results may not be correct");
+
+		if (json.has("classRefOp"))
+		    this.addWarning("classRefOp is not yet supported - " +
+				    "results may not be correct");
 
 		if (number > 0) {
 		    if (operands.size() != 1)
@@ -380,9 +385,7 @@
 			);
 
 		    if (DEBUG)
-			log.trace("Found Class definition for {}", json.get("class").asInt(0));
-
-		    number = json.get("class").asInt(0);
+			log.trace("Found Class definition for {}", number);
 
 		    if (number > MAX_CLASS_NUM) {
 			throw new QueryException(
@@ -446,6 +449,9 @@
 		    return sqw.setMin(min).setMax(max);
 
 		return new SpanRepetitionQueryWrapper(sqw, min, max);
+
+	    case "operation:relation":
+		throw new QueryException(613, "Relations are not yet supported");
 	    };
 
 	    throw new QueryException(613, "Unknown group operation");
@@ -650,7 +656,8 @@
 	    return this.seg(value.toString());
 
 	if (json.has("attr"))
-	    throw new QueryException(613, "Attributes not yet supported in spans");
+	    this.addWarning("Attributes are not yet supported - " +
+			    "results may not be correct");
 
 	return this.tag(value.toString());
     };
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index 935635a..b56a6d0 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -83,9 +83,16 @@
 		this.error = "No query defined";
 	    };
 
-	    // Report warning coming from the request
+	    // Legacy code: Report warning coming from the request
 	    if (this.request.has("warning"))
 		this.addWarning(this.request.get("warning").asText());
+	    if (this.request.has("warnings")) {
+		JsonNode warnings = this.request.get("warnings");
+		for (JsonNode node : warnings)
+		    this.addWarning(node.asText());
+	    };
+	    // end of legacy code
+
 	    
 	    // virtual collections
 	    if (this.request.has("collections") ||
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
index fe671ec..4ed1223 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
@@ -137,7 +137,11 @@
 	// Embed a sequence
 	if (ssq instanceof SpanSequenceQueryWrapper) {
 
+	    if (DEBUG)
+		log.trace("Add SpanSequenceQueryWrapper to sequence");
+
 	    // There are no constraints - just next spans
+	    // Flatten!
 	    SpanSequenceQueryWrapper ssqw = (SpanSequenceQueryWrapper) ssq;
 	    if (!this.hasConstraints() &&
 		!ssqw.hasConstraints() &&
@@ -145,6 +149,11 @@
 		for (int i = 0; i < ssqw.segments.size(); i++) {
 		    this.append(ssqw.segments.get(i));
 		};
+	    }
+
+	    // No flattening
+	    else {
+		this.segments.add(ssq);
 	    };
 	}
 
@@ -187,6 +196,7 @@
 	if (ssq instanceof SpanSequenceQueryWrapper) {
 
 	    // There are no constraints - just next spans
+	    // Flatten!
 	    SpanSequenceQueryWrapper ssqw = (SpanSequenceQueryWrapper) ssq;
 	    if (!this.hasConstraints() &&
 		!ssqw.hasConstraints() &&
@@ -194,6 +204,11 @@
 		for (int i = ssqw.segments.size() - 1; i >= 0; i--) {
 		    this.prepend(ssqw.segments.get(i));
 		};
+	    }
+
+	    // No flattening
+	    else {
+		this.segments.add(0, ssq);
 	    };
 	}
 
@@ -453,6 +468,8 @@
 
 		// [problem][anchor]
 		if (i < (size-1) && this.segments.get(i+1).maybeAnchor()) {
+		    if (DEBUG)
+			log.trace("Situation is [problem][anchor]");
 
 		    // Insert the solution
 		    try {
@@ -471,10 +488,16 @@
 
 		    if (DEBUG)
 			log.trace("Remove segment {} - now size {}", i, size);
+
+		    // Restart checking
+		    i = 0;
 		}
 
 		// [anchor][problem]
 		else if (i >= 1 && this.segments.get(i-1).maybeAnchor()) {
+		    if (DEBUG)
+			log.trace("Situation is [anchor][problem]");
+
 		    // Insert the solution
 		    try {
 			this.segments.set(
@@ -492,13 +515,21 @@
 
 		    if (DEBUG)
 			log.trace("Remove segment {} - now size {}", i, size);
+
+		    // Restart checking
+		    i = 0;
 		}
+		// [problem][problem]
 		else {
+		    if (DEBUG)
+			log.trace("Situation is [problem][problem]");
 		    noRemainingProblem = false;
 		    i++;
 		};
 	    }
 	    else {
+		if (DEBUG)
+		    log.trace("segment {} can be an anchor", i);
 		i++;
 	    };
 	};
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQueryJSON.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQueryJSON.java
index d46c9e2..766d6ee 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQueryJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQueryJSON.java
@@ -224,6 +224,7 @@
 	assertEquals("spanExpansion(spanExpansion(tokens:tt/p:NN, !tokens:tt/p:DET{1, 1}, right), !tokens:tt/p:ADJ{1, 1}, right)", sqwi.toQuery().toString());
     };
 
+
     @Test
     public void queryJSONseqNegativeEndSequence2 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQueryFile("negative-last-sequence-2.jsonld");
@@ -233,6 +234,13 @@
 	assertEquals("spanExpansion(spanExpansion(tokens:tt/p:ADJ, !tokens:tt/p:DET{1, 1}, left), !tokens:tt/p:NN{1, 1}, left)", sqwi.toQuery().toString());
     };
 
+    @Test
+    public void queryJSONseqMultipleDistances () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQueryFile("multiple-distances.jsonld");
+	// er []{,10} kann []{1,10} sagte 
+
+	assertEquals("spanDistance(tokens:s:er, spanDistance(tokens:s:kann, tokens:s:sagte, [(w[2:11], ordered, notExcluded)]), [(w[1:11], ordered, notExcluded)])", sqwi.toQuery().toString());
+    };
 
 
     // get query wrapper based on json file
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
index 36632e6..8c407ad 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
@@ -747,6 +747,48 @@
 	assertEquals(345, res.at("/matches/0/tokens/2/1").asInt());
     };
 
+    @Test
+    public void searchJSONmultitermRewriteBug () throws IOException {
+	// Construct index
+	KorapIndex ki = new KorapIndex();
+	// Indexing test files
+	ki.addDocFile(
+            1,getClass().getResource("/bzk/D59-00089.json.gz").getFile(), true
+	);
+	ki.addDocFile(
+            2,getClass().getResource("/bzk/D59-00089.json.gz").getFile(), true
+	);
+
+	ki.commit();
+
+	String json = getString(
+	    getClass().getResource("/queries/bugs/multiterm_rewrite.jsonld").getFile()
+        );
+	
+	KorapSearch ks = new KorapSearch(json);
+	KorapResult kr = ks.run(ki);
+	assertEquals(kr.getQuery(),"");
+
+
+	/*
+
+	assertEquals(
+            kr.getQuery(),
+	    "{4: spanNext({1: spanNext({2: tokens:s:ins}, {3: tokens:s:Leben})}, tokens:s:gerufen)}"
+        );
+	assertEquals(
+	    kr.getMatch(0).getSnippetBrackets(),
+	    "... sozialistischen Initiative\" eine neue politische Gruppierung " +
+	    "[{4:{1:{2:ins} {3:Leben}} gerufen}] hatten. " +
+	    "Pressemeldungen zufolge haben sich in ..."
+        );
+
+	assertEquals(2, kr.getTotalResults());
+	assertEquals(0, kr.getStartIndex());
+	*/
+    };
+
+
 
     @Test
     public void searchJSONCollection () throws IOException {
diff --git a/src/test/resources/queries/bsp-class.jsonld b/src/test/resources/queries/bsp-class.jsonld
index 075f927..b4fd65e 100644
--- a/src/test/resources/queries/bsp-class.jsonld
+++ b/src/test/resources/queries/bsp-class.jsonld
@@ -3,7 +3,7 @@
   "query":{
     "@type":"korap:group",
     "operation" : "operation:class",
-   "class":0,
+   "class":1,
     "operands":[
       {
 	"@type":"korap:group",
diff --git a/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld b/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld
new file mode 100644
index 0000000..bd0c08b
--- /dev/null
+++ b/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld
@@ -0,0 +1,65 @@
+{
+  "@context": "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+  "warnings":[
+    "This is a warning coming from the serialization"
+  ],
+  "query": {
+    "@type" : "korap:reference",
+    "classRef" : [
+      130
+    ],
+    "operands" : [
+      {
+        "@type" : "korap:group",
+        "class" : 131,
+        "classIn" : [
+          129,
+          130
+        ],
+        "classOut" : 131,
+        "classRefCheck" : "classRefCheck:includes",
+        "operands" : [
+          {
+            "@type" : "korap:group",
+            "frame" : "frame:contains",
+            "frames" : [],
+            "operands" : [
+              {
+                "@type" : "korap:group",
+                "class" : 129,
+                "classOut" : 129,
+                "operands" : [
+                  {
+                    "@type" : "korap:span",
+                    "key" : "s"
+                  }
+                ],
+                "operation" : "operation:class"
+              },
+              {
+                "@type" : "korap:group",
+                "class" : 130,
+                "classOut" : 130,
+                "operands" : [
+                  {
+                    "@type" : "korap:token",
+                    "wrap" : {
+                      "@type" : "korap:term",
+                      "key" : "wegen",
+                      "layer" : "orth",
+                      "match" : "match:eq"
+                    }
+                  }
+                ],
+                "operation" : "operation:class"
+              }
+            ],
+            "operation" : "operation:position"
+          }
+        ],
+        "operation" : "operation:class"
+      }
+    ],
+    "operation" : "operation:focus"
+  }
+}
diff --git a/src/test/resources/queries/bugs/multiterm_rewrite.jsonld b/src/test/resources/queries/bugs/multiterm_rewrite.jsonld
new file mode 100644
index 0000000..c07f88c
--- /dev/null
+++ b/src/test/resources/queries/bugs/multiterm_rewrite.jsonld
@@ -0,0 +1,64 @@
+{
+  "@context":"http://ids-mannheim.de/ns/KorAP/json-ld/v0.2/context.jsonld",
+  "errors":[],
+  "warnings":[],
+  "announcements":[
+    "Deprecated 2014-07-24: 'min' and 'max' to be supported until 3 months from deprecation date."
+  ],
+  "collection":{},
+  "meta":{
+    "startPage":1,
+    "context":"paragraph"
+  },
+  "query":{
+    "@type":"korap:group",
+    "operation":"operation:sequence",
+    "operands":[
+      {
+	"@type":"korap:group",
+	"operation":"operation:repetition",
+	"operands":[
+	  {
+	    "@type":"korap:token",
+	    "wrap":{
+	      "@type":"korap:term",
+	      "foundry":"tt",
+	      "layer":"p",
+	      "type":"type:regex",
+	      "key":"A.*",
+	      "match":"match:eq"
+	    }
+	  }
+	],
+	"boundary":{
+	  "@type":"korap:boundary",
+	  "min":0,
+	  "max":3
+	},
+	"min":0,
+	"max":3
+      },
+      {
+	"@type":"korap:token",
+	"wrap":{
+	  "@type":"korap:term",
+	  "foundry":"tt",
+	  "layer":"p",
+	  "type":"type:regex",
+	  "key":"N.*",
+	  "match":"match:eq"
+	}
+      }
+    ]
+  },
+  "collections":[
+    {
+      "@type":"korap:meta-filter",
+      "@value":{
+	"@type":"korap:term",
+	"@field":"korap:field#corpusID",
+	"@value":"WPD"
+      }
+    }
+  ]
+}
diff --git a/src/test/resources/queries/sequence/multiple-distances.jsonld b/src/test/resources/queries/sequence/multiple-distances.jsonld
new file mode 100644
index 0000000..4187ded
--- /dev/null
+++ b/src/test/resources/queries/sequence/multiple-distances.jsonld
@@ -0,0 +1,70 @@
+{
+  "@context": "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+  "query": {
+    "@type" : "korap:group",
+    "distances" : [
+      {
+        "@type" : "korap:distance",
+        "boundary" : {
+          "@type" : "korap:boundary",
+          "max" : 11,
+          "min" : 1
+        },
+        "key" : "w",
+        "max" : 11,
+        "min" : 1
+      }
+    ],
+    "inOrder" : true,
+    "operands" : [
+      {
+        "@type" : "korap:token",
+        "wrap" : {
+          "@type" : "korap:term",
+          "key" : "er",
+          "layer" : "orth",
+          "match" : "match:eq"
+        }
+      },
+      {
+        "@type" : "korap:group",
+        "distances" : [
+          {
+            "@type" : "korap:distance",
+            "boundary" : {
+              "@type" : "korap:boundary",
+              "max" : 11,
+              "min" : 2
+            },
+            "key" : "w",
+            "max" : 11,
+            "min" : 2
+          }
+        ],
+        "inOrder" : true,
+        "operands" : [
+          {
+            "@type" : "korap:token",
+            "wrap" : {
+              "@type" : "korap:term",
+              "key" : "kann",
+              "layer" : "orth",
+              "match" : "match:eq"
+            }
+          },
+          {
+            "@type" : "korap:token",
+            "wrap" : {
+              "@type" : "korap:term",
+              "key" : "sagte",
+              "layer" : "orth",
+              "match" : "match:eq"
+            }
+          }
+        ],
+        "operation" : "operation:sequence"
+      }
+    ],
+    "operation" : "operation:sequence"
+  }
+}