resource mapping, cosmas2: element attributes
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
index c7b1655..e6d94ad 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
@@ -33,6 +33,14 @@
 		return term;
 	}
 	
+	protected LinkedHashMap<String, Object> makeTermGroup(String relation) {
+		LinkedHashMap<String, Object> term = new LinkedHashMap<String, Object>();
+		term.put("@type", "korap:termGroup");
+		term.put("relation", "relation:"+relation);
+		term.put("operands", new ArrayList<Object>());
+		return term;
+	}
+	
 	protected LinkedHashMap<String, Object> makeToken() {
 		LinkedHashMap<String, Object> token = new LinkedHashMap<String, Object>();
 		token.put("@type", "korap:token");
@@ -68,6 +76,15 @@
 		group.put("max", max);
 		return group;
 	}
+
+	protected LinkedHashMap<String, Object> makeDistance(String key, int min, int max) {
+		LinkedHashMap<String, Object> group = new LinkedHashMap<String, Object>();
+		group.put("@type", "korap:distance");
+		group.put("key", key);
+		group.put("min", min);
+		group.put("max", max);
+		return group;
+	}
 	
 	protected void addOperandsToGroup(LinkedHashMap<String, Object> group) {
 		ArrayList<Object> operands = new ArrayList<Object>();
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 f66fabf..a5c6969 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
@@ -69,6 +69,10 @@
 	 * Flag that indicates whether token fields or meta fields are currently being processed
 	 */
 	boolean inMeta = false;
+	/**
+	 * 
+	 */
+	int classRefCounter = 1;
 	boolean negate = false;
 	
 	Tree cosmasTree;
@@ -139,6 +143,7 @@
 		processNode(tree);
 	}
 	
+	@SuppressWarnings("unchecked")
 	private void processNode(Tree node) {
 		
 		// Top-down processing
@@ -301,7 +306,46 @@
 			// Step I: create element
 			LinkedHashMap<String, Object> elem = new LinkedHashMap<String, Object>();
 			elem.put("@type", "korap:span");
-			elem.put("key", node.getChild(0).getChild(0).toStringTree().toLowerCase());
+			if (node.getChild(0).toStringTree().equals("EMPTY")) {
+				
+			} else {
+				int elname = 0;
+				Tree elnameNode = getFirstChildWithCat(node, "ELNAME");
+				if (elnameNode != null) {
+					elem.put("key", elnameNode.getChild(0).toStringTree().toLowerCase());
+					elname = 1;
+				}
+				if (node.getChildCount() > elname) {
+					LinkedHashMap<String, Object> termGroup = makeTermGroup("and");
+					ArrayList<Object> termGroupOperands = (ArrayList<Object>) termGroup.get("operands"); 
+					for (int i=elname; i<node.getChildCount(); i++) {
+						Tree attrNode = node.getChild(i);
+						if (attrNode.getChildCount()==2) {
+							LinkedHashMap<String, Object> term = makeTerm();
+							termGroupOperands.add(term);
+							String layer = attrNode.getChild(0).toStringTree();
+							term.put("layer", translateMorph(layer));
+							term.put("key", attrNode.getChild(1).toStringTree());
+							term.put("match", "match:eq");
+						} else {
+							for (int j=1; j<attrNode.getChildCount(); j++) {
+								LinkedHashMap<String, Object> term = makeTerm();
+								termGroupOperands.add(term);
+								String layer = attrNode.getChild(0).toStringTree();
+								term.put("layer", translateMorph(layer));
+								term.put("key", attrNode.getChild(j).toStringTree());
+								term.put("match", "match:eq");
+							}
+						}
+						 
+						
+						if (getNodeCat(attrNode).equals("NOTEQ")) negate=true;
+						
+					}
+					elem.put("attr", termGroup);
+				}
+			}
+			
 			//Step II: decide where to put
 			putIntoSuperObject(elem);
 		}		
@@ -407,7 +451,7 @@
 			submatchgroup.put("@type", "korap:group");
 			submatchgroup.put("operation", "operation:"+ "submatch");
 			ArrayList<Integer> classRef = new ArrayList<Integer>();
-			classRef.add(1);
+			classRef.add(classRefCounter);
 			submatchgroup.put("classRef", classRef);
 			
 			ArrayList<Object> submatchoperands = new ArrayList<Object>(); 
@@ -439,7 +483,8 @@
 			LinkedHashMap<String, Object> classGroup = new LinkedHashMap<String, Object>();
 			classGroup.put("@type", "korap:group");
 			classGroup.put("operation", "operation:"+ "class");
-			classGroup.put("class", 1);
+			classGroup.put("class", classRefCounter);
+			classRefCounter++;
 			classGroup.put("operands", new ArrayList<Object>());
 			objectStack.push(classGroup);
 			stackedObjects++;
@@ -453,7 +498,8 @@
 			LinkedHashMap<String, Object> classGroup = new LinkedHashMap<String, Object>();
 			classGroup.put("@type", "korap:group");
 			classGroup.put("operation", "operation:"+ "class");
-			classGroup.put("class", 2);
+			classGroup.put("class", classRefCounter);
+			classRefCounter++;
 			classGroup.put("operands", new ArrayList<Object>());
 			objectStack.push(classGroup);
 			stackedObjects++;
@@ -467,8 +513,12 @@
 			exclGroup.put("@type", "korap:group");
 			exclGroup.put("operation", "operation:"+ "submatch");
 			ArrayList<Integer> classRef = new ArrayList<Integer>();
-			classRef.add(1);
-			classRef.add(2);
+			
+			classRef.add(classRefCounter);
+//			classRefCounter++;
+			 // yes, do this twice!
+			classRef.add(classRefCounter+1);
+//			classRefCounter++;
 			exclGroup.put("classRef", classRef);
 			exclGroup.put("classRefOp", "classRefOp:"+"intersection");
 			ArrayList<Object> operands = new ArrayList<Object>();
@@ -537,7 +587,8 @@
 				LinkedHashMap<String, Object> classGroup = new LinkedHashMap<String, Object>();
 				classGroup.put("@type", "korap:group");
 				classGroup.put("operation", "operation:class");
-				classGroup.put("class", 1);
+				classGroup.put("class", classRefCounter);
+				classRefCounter++;
 				classGroup.put("operands", new ArrayList<Object>());
 				objectStack.push(classGroup);
 				stackedObjects++;
@@ -584,7 +635,8 @@
 					LinkedHashMap<String, Object> classGroup = new LinkedHashMap<String, Object>();
 					classGroup.put("@type", "korap:group");
 					classGroup.put("operation", "operation:class");
-					classGroup.put("class", 1);
+					classGroup.put("class", classRefCounter);
+					classRefCounter++;
 					ArrayList<Object> classOperands = new ArrayList<Object>(); 
 					classGroup.put("operands", classOperands);
 					distributedOperands.add(classOperands);  // subtree to be put into every class group -> distribute
@@ -646,6 +698,15 @@
 	
 	
 
+	private Object translateMorph(String layer) {
+		LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
+		map.put("ANA", "pos");
+		if (map.containsKey(layer))
+			return map.get(layer);
+		else
+			return layer;
+	}
+
 	private void parseOPINOptions(Tree node, LinkedHashMap<String, Object> posgroup) {
 		Tree posnode = getFirstChildWithCat(node, "POS");
 		Tree rangenode = getFirstChildWithCat(node, "RANGE");
@@ -830,16 +891,21 @@
 //				"Mann /t0 Frau",
 				"sagt der:sa Bundeskanzler",
 //				"Der:sa,-pe,+te ",
+				"#ELEM(W POS!='N V' title=tada)",
+				"#ELEM(W ANA != 'N V')"
+//				"(&Baum #IN #ELEM(NP)) #IN(L) #ELEM(S)"
 				};
 //		CosmasTree.debug=true;
 		for (String q : queries) {
 			try {
 				System.out.println(q);
 				try {
-					@SuppressWarnings("unused")
 					CosmasTree act = new CosmasTree(q);
+					System.out.println(act.parseCosmasQuery(q).toStringTree());
 				} catch (QueryException e) {
 					e.printStackTrace();
+				} catch (RecognitionException e) {
+					e.printStackTrace();
 				}
 				System.out.println();
 				
diff --git a/src/test/java/CosmasTreeTest.java b/src/test/java/CosmasTreeTest.java
index 10b6ed8..777b75a 100644
--- a/src/test/java/CosmasTreeTest.java
+++ b/src/test/java/CosmasTreeTest.java
@@ -464,6 +464,44 @@
 		ct = new CosmasTree(query);
 		map = ct.getRequestMap().get("query").toString();
 		assertEquals(elem1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		query="#ELEM(W ANA=N)";
+		String elem2 = 
+			"{@type=korap:span, key=w, attr=" +
+				"{@type=korap:termGroup, relation=relation:and, operands=[" +
+					"{@type=korap:term, layer=pos, key=N, match=match:eq}" +
+				"]}" +
+			"}";
+		ct = new CosmasTree(query);
+		map = ct.getRequestMap().get("query").toString();
+		assertEquals(elem2.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		query="#ELEM(W ANA != 'N V')";
+		String elem3 = 
+			"{@type=korap:span, key=w, attr=" +
+				"{@type=korap:termGroup, relation=relation:and, operands=[" +
+					"{@type=korap:term, layer=pos, key=N, match=match:eq}," +
+					"{@type=korap:term, layer=pos, key=V, match=match:eq}" +
+				"]}" +
+			"}";
+		ct = new CosmasTree(query);
+		map = ct.getRequestMap().get("query").toString();
+		assertEquals(elem3.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		query="#ELEM(W ANA != 'N V' Genre = Sport)";
+		String elem4 = 
+			"{@type=korap:span, key=w, attr=" +
+				"{@type=korap:termGroup, relation=relation:and, operands=[" +
+					"{@type=korap:termGroup, relation=relation:and, operands=[" +
+						"{@type=korap:term, layer=pos, key=N, match=match:eq}," +
+						"{@type=korap:term, layer=pos, key=V, match=match:eq}" +
+					"]}" +
+					"{@type=korap:term, layer=Genre, key=Sport, match=match:eq}" +
+				"]}" +
+			"}";
+		ct = new CosmasTree(query);
+		map = ct.getRequestMap().get("query").toString();
+		assertEquals(elem4.replaceAll(" ", ""), map.replaceAll(" ", ""));
 	}
 	
 	@Test
@@ -558,7 +596,7 @@
 						"]}," +
 						"{@type=korap:group, operation=operation:position, frame=frame:startswith, exclude=true, operands=[" +
 							"{@type=korap:span, key=p}," +
-							"{@type=korap:group, operation=operation:class, class=1, operands=[" +
+							"{@type=korap:group, operation=operation:class, class=2, operands=[" +
 								"{@type=korap:group, operation=operation:sequence, operands=[" +
 									"{@type=korap:token, wrap={@type=korap:term, key=der, layer=orth, match=match:eq}}," +
 									"{@type=korap:token, wrap={@type=korap:term, key=Mann, layer=orth, match=match:eq}}" +
@@ -603,13 +641,13 @@
 						"]}," +
 						"{@type=korap:group, operation=operation:position, frame=frame:startswith, exclude=true, operands=[" +
 							"{@type=korap:span, key=p}," +
-							"{@type=korap:group, operation=operation:class, class=1, operands=[" +
+							"{@type=korap:group, operation=operation:class, class=2, operands=[" +
 									"{@type=korap:token, wrap={@type=korap:term, key=Mann, layer=orth, match=match:eq}}" +
 							"]}" +
 						"]}," +
 						"{@type=korap:group, operation=operation:position, frame=frame:endswith, operands=[" +
 							"{@type=korap:span, key=t}," +
-							"{@type=korap:group, operation=operation:class, class=1, operands=[" +
+							"{@type=korap:group, operation=operation:class, class=3, operands=[" +
 									"{@type=korap:token, wrap={@type=korap:term, key=Mann, layer=orth, match=match:eq}}" +
 						"]}" +
 					"]}" +