cosmas distance operator now contains 'constraint' field for all given distance constraints
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
index 835e82a..d69753d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
@@ -327,32 +327,66 @@
 		}
 		
 		if (nodeCat.equals("OPPROX")) {
-			// Step I: create group
-			LinkedHashMap<String, Object> proxGroup = new LinkedHashMap<String, Object>();
-			proxGroup.put("@type", "korap:group");
-			proxGroup.put("relation", "distance");
-
 			// collect info
 			Tree prox_opts = node.getChild(0);
 			Tree typ = prox_opts.getChild(0);
 			Tree dist_list = prox_opts.getChild(1);
-			String direction = dist_list.getChild(0).getChild(0).getChild(0).toStringTree();
-			String min = dist_list.getChild(0).getChild(1).getChild(0).toStringTree();
-			String max = dist_list.getChild(0).getChild(1).getChild(1).toStringTree();
-			String meas = dist_list.getChild(0).getChild(2).getChild(0).toStringTree();
-			
-			if (min.equals("VAL0")) {
-				min=max;
-			}
-			
-			String subtype = typ.getChild(0).toStringTree().equals("PROX") ? "incl" : "excl"; 
-			proxGroup.put("@subtype", subtype);
-			proxGroup.put("measure", meas);
-			proxGroup.put("min", min);
-			proxGroup.put("max", max);
-			proxGroup.put("operands", new ArrayList<Object>());
+			// Step I: create group
+			LinkedHashMap<String, Object> proxGroup = new LinkedHashMap<String, Object>();
+			proxGroup.put("@type", "korap:group");
+			proxGroup.put("relation", "distance");
 			objectStack.push(proxGroup);
 			stackedObjects++;
+			ArrayList<Object> constraints = new ArrayList<Object>();
+			String subtype = typ.getChild(0).toStringTree().equals("PROX") ? "incl" : "excl"; 
+			proxGroup.put("@subtype", subtype);
+			proxGroup.put("constraint", constraints);
+			proxGroup.put("operands", new ArrayList<Object>());
+			
+			// if only one dist_info, put directly into constraints
+			if (dist_list.getChildCount()==1) {
+				String direction = dist_list.getChild(0).getChild(0).getChild(0).toStringTree().toLowerCase();
+				String min = dist_list.getChild(0).getChild(1).getChild(0).toStringTree();
+				String max = dist_list.getChild(0).getChild(1).getChild(1).toStringTree();
+				String meas = dist_list.getChild(0).getChild(2).getChild(0).toStringTree();
+				if (min.equals("VAL0")) {
+					min=max;
+				}
+				LinkedHashMap<String, Object> distance = new LinkedHashMap<String, Object>();
+				distance.put("@type", "korap:distance");
+				distance.put("measure", meas);
+				distance.put("direction", direction);
+				distance.put("min", min);
+				distance.put("max", max);
+				constraints.add(distance);
+				
+			}
+			// otherwise, create group and add info there
+			else {
+				LinkedHashMap<String, Object> distanceGroup = new LinkedHashMap<String, Object>();
+				ArrayList<Object> groupOperands = new ArrayList<Object>();
+				distanceGroup.put("@type", "korap:group");
+				distanceGroup.put("relation", "and");
+				distanceGroup.put("operands", groupOperands);
+				constraints.add(distanceGroup);
+				for (int i=0; i<dist_list.getChildCount(); i++) {
+					String direction = dist_list.getChild(i).getChild(0).getChild(0).toStringTree().toLowerCase();
+					String min = dist_list.getChild(i).getChild(1).getChild(0).toStringTree();
+					String max = dist_list.getChild(i).getChild(1).getChild(1).toStringTree();
+					String meas = dist_list.getChild(i).getChild(2).getChild(0).toStringTree();
+					if (min.equals("VAL0")) {
+						min=max;
+					}
+					LinkedHashMap<String, Object> distance = new LinkedHashMap<String, Object>();
+					distance.put("@type", "korap:distance");
+					distance.put("measure", meas);
+					distance.put("direction", direction);
+					distance.put("min", min);
+					distance.put("max", max);
+					groupOperands.add(distance);
+				}
+			}
+			
 			
 			// Step II: decide where to put
 			if (objectStack.size()>1) {
@@ -387,6 +421,29 @@
 			}
 		}
 		
+		if (nodeCat.equals("OPALL") || nodeCat.equals("OPNHIT")) {
+			// Step I: create group
+			LinkedHashMap<String, Object> allgroup = new LinkedHashMap<String, Object>();
+			allgroup.put("@type", "korap:group");
+			String scope = nodeCat.equals("OPALL") ? "all" : "nhit";
+			allgroup.put("relation", scope);
+			// add optional position info, if present
+			if (QueryUtils.getNodeCat(node.getChild(0)).equals("POS")) {
+				allgroup.put("position", node.getChild(0).getChild(0).toStringTree());
+			}
+			allgroup.put("operands", new ArrayList<Object>());
+			objectStack.push(allgroup);
+			stackedObjects++;
+			
+			// Step II: decide where to put
+			if (objectStack.size()>1) {
+				ArrayList<Object> topObjectOperands = (ArrayList<Object>) objectStack.get(1).get("operands");
+				topObjectOperands.add(allgroup);
+			} else {
+				requestMap.put("query", allgroup);
+			}
+		}
+		
 		if (nodeCat.equals("OPEND") || nodeCat.equals("OPBEG")) {
 			// Step I: create group
 			LinkedHashMap<String, Object> ingroup = new LinkedHashMap<String, Object>();
@@ -504,11 +561,15 @@
 //				"Sonne oder Mond oder Sterne",
 //				"Mann #OV (der Mann)",
 //				"Mann #OV(L) der Mann"
-				"*tür",
-				"#BED(tür,sa)",
-				"das %w3 Haus",
-				"das /w3 Haus"
-				
+//				"*tür",
+//				"#BED(der, sa)",
+//				"das %w3 Haus",
+//				"das /w3 Haus"
+				"#ALL(gehen /w1:10 voran)",
+				"#NHIT(gehen /w1:10 voran)",
+				"das /w1:2,s0 Haus",
+				"das /w1:2 Haus und Hof",
+				"nicht Frau"
 				};
 		CosmasTree.debug=true;
 		for (String q : queries) {
diff --git a/src/test/java/CosmasTreeTest.java b/src/test/java/CosmasTreeTest.java
index f111c56..11cd197 100644
--- a/src/test/java/CosmasTreeTest.java
+++ b/src/test/java/CosmasTreeTest.java
@@ -169,13 +169,37 @@
 	public void testOPPROX() {
 		query="Sonne /+w1:4 Mond";
 		String prox1 = 
-					"{@type=korap:group, relation=distance, @subtype=incl, measure=w, min=1, max=4, operands=[" +
-						"{@type=korap:token, @value={@type=korap:term, @value=orth:Sonne, relation==}}," +
-						"{@type=korap:token, @value={@type=korap:term, @value=orth:Mond, relation==}}" +
-					"]}";
+					"{@type=korap:group, relation=distance, @subtype=incl, " +
+						"constraint=[" +
+							"{@type=korap:distance, measure=w, direction=plus, min=1, max=4}" +
+						"], " +
+						"operands=[" +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:Sonne, relation==}}," +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:Mond, relation==}}" +
+						"]" +
+					"}";
 		ppt = new CosmasTree(query);
 		map = ppt.getRequestMap().get("query").toString();
 		assertEquals(prox1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		query="Sonne /+w1:4,s0,p1:3 Mond";
+		String prox2 = 
+					"{@type=korap:group, relation=distance, @subtype=incl, " +
+						"constraint=[" +
+							"{@type=korap:group, relation=and, operands=[" +
+								"{@type=korap:distance, measure=w, direction=plus, min=1, max=4}," +
+								"{@type=korap:distance, measure=s, direction=both, min=0, max=0}," +
+								"{@type=korap:distance, measure=p, direction=both, min=1, max=3}" +
+							"]}" +
+						"], " +
+						"operands=[" +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:Sonne, relation==}}," +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:Mond, relation==}}" +
+						"]" +
+					"}";
+		ppt = new CosmasTree(query);
+		map = ppt.getRequestMap().get("query").toString();
+		assertEquals(prox2.replaceAll(" ", ""), map.replaceAll(" ", ""));
 	}
 	
 	@Test
@@ -248,32 +272,60 @@
 		// http://www.ids-mannheim.de/cosmas2/web-app/hilfe/suchanfrage/eingabe-zeile/syntax/links.html
 		// http://www.ids-mannheim.de/cosmas2/web-app/hilfe/suchanfrage/eingabe-zeile/syntax/rechts.html
 		// http://www.ids-mannheim.de/cosmas2/web-app/hilfe/suchanfrage/eingabe-zeile/thematische-bsp/bsp-satzlaenge.html
+		query="";
 	}
 	
 
 	@Test
 	public void testELEM() {
 		// http://www.ids-mannheim.de/cosmas2/web-app/hilfe/suchanfrage/eingabe-zeile/syntax/elem.html
+		//XXX NOT WORKING IN ANTLR GRAMMAR! ELEM(S) returns (C2PQ (OPWF "ELEM") (OPWF "S"))
 	}
 	
 	@Test
 	public void testOPALL() {
-		
+		query="#ALL(gehen /w1:10 voran)";
+		String all1 = 
+				"{@type=korap:group, relation=all, operands=[" +
+					"{@type=korap:group, relation=distance, @subtype=incl, " +
+						"constraint=[" +
+							"{@type=korap:distance, measure=w, direction=both, min=1, max=10}" +
+						"], " +
+						"operands=[" +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:gehen, relation==}}," +
+							"{@type=korap:token, @value={@type=korap:term, @value=orth:voran, relation==}}" +
+						"]" +
+					"}" +
+				"]}";
+		ppt = new CosmasTree(query);
+		map = ppt.getRequestMap().get("query").toString();
+		assertEquals(all1.replaceAll(" ", ""), map.replaceAll(" ", ""));
 	}
 	
 	@Test
 	public void testOPNHIT() {
-		
+		query="#NHIT(gehen /w1:10 voran)";
+		String nhit1 = 
+				"{@type=korap:group, relation=nhit, operands=[" +
+						"{@type=korap:group, relation=distance, @subtype=incl, " +
+							"constraint=[" +
+								"{@type=korap:distance, measure=w, direction=both, min=1, max=10}" +
+							"], " +
+							"operands=[" +
+								"{@type=korap:token, @value={@type=korap:term, @value=orth:gehen, relation==}}," +
+								"{@type=korap:token, @value={@type=korap:term, @value=orth:voran, relation==}}" +
+							"]" +
+						"}" +
+					"]}";
+		ppt = new CosmasTree(query);
+		map = ppt.getRequestMap().get("query").toString();
+		assertEquals(nhit1.replaceAll(" ", ""), map.replaceAll(" ", ""));
 	}
 	
 	@Test
 	public void testOPBED() {
-		
+		//XXX NOT WORKING IN ANTLR GRAMMAR! #BED(der, sa) returns (C2PQ (OPBED (OPWF "der,") (OPWF "sa") (OPTS <mismatched token: [@3,12:12=')',<45>,1:12], resync=)>)))
 	}
 	
-	// TODO
-	/*
-	 * 
-	 */
 }