PQ quantification in position bugfix
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
index 38d26eb..79393e0 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
@@ -209,7 +209,7 @@
 		
 		if (debug) {
 			System.err.println(" "+objectStack);
-			System.err.println(" "+tokenStack);
+//			System.err.println(" "+tokenStack);
 			System.out.println(openNodeCats);
 		}
 		
@@ -288,9 +288,7 @@
 				} else {
 					// if only child, make the sequence a mere token...
 					// ... but only if it has a real token/element beneath it
-					if (QueryUtils.getNodeCat(node.getChild(0)).equals("cq_segment")
-						|| QueryUtils.getNodeCat(node.getChild(0)).equals("sq_segment")
-						|| QueryUtils.getNodeCat(node.getChild(0)).equals("element")	) {
+					if (! QueryUtils.isContainerOnly(node)) {
 						sequence.put("@type", "korap:token");
 						tokenStack.push(sequence);
 						stackedTokens++;
@@ -298,7 +296,7 @@
 						stackedObjects++;
 					// else, it's a group (with shrink()/spanclass/align... as child)
 					} else {
-						sequence.put("@type", "korap:group");
+//						sequence.put("@type", "korap:group");
 //						objectStack.push(sequence);
 //						stackedObjects++;
 					}
@@ -308,7 +306,7 @@
 				if (cqHasOccSibling) {
 					ArrayList<Object> topGroupOperands = (ArrayList<Object>) objectStack.get(1).get("operands");
 					topGroupOperands.add(sequence);
-				// ...if not modified by occurrence, put into suitable super structure
+				// ...if not modified by occurrence, put into appropriate super object
 				} else {
 					if (openNodeCats.get(1).equals("query")) {
 						// cq_segment is top query node
@@ -346,8 +344,17 @@
 					} else if (!objectStack.isEmpty()){
 						// embed in super sequence
 						System.out.println(objectStack);
-						ArrayList<Object> topSequenceOperands = (ArrayList<Object>) objectStack.get(1).get("operands");
-						topSequenceOperands.add(sequence);
+						ArrayList<Object> topSequenceOperands;
+						if (! QueryUtils.isContainerOnly(node)) {
+							try {
+								topSequenceOperands = (ArrayList<Object>) objectStack.get(1).get("operands");
+								topSequenceOperands.add(sequence);
+							} catch (IndexOutOfBoundsException e) {
+//								topSequenceOperands = (ArrayList<Object>) objectStack.get(0).get("operands");
+							}
+						}
+						
+						
 					}
 				}
 			}
@@ -403,7 +410,9 @@
 			stackedObjects++;
 			// add group to sequence only if it is not an only child (in that case, cq_segments has already added the info and is just waiting for the values from "field")
 			// take into account a possible 'occ' child
-			if (node.getParent().getChildCount()>1) {
+			System.out.println(objectStack);
+//			if (node.getParent().getChildCount()>1) {
+			if (objectStack.size()>1) {
 				ArrayList<Object> topSequenceOperands = (ArrayList<Object>) objectStack.get(1).get("operands");
 				topSequenceOperands.add(group);
 			} else {
@@ -991,8 +1000,6 @@
 		/*
 		 * For testing
 		 */
-		
-		
 		String[] queries = new String[] {
 				"shrink(1|2:{1:[base=der]}{2:[base=Mann]})",
 				"{[base=Mann]}",
@@ -1002,10 +1009,7 @@
 				"<cnx/c=np>",
 				"contains(<cnx/c=np>, [mate/pos=NE])",
 				"matches(<A>,[pos=N]*)",
-				"matches(<A>,[pos=N]{4})",
-				"([base=bar][base=foo])*"
-//				"matches(<A>,[pos=N])",
-//				"[pos=V]{3}"
+				"[base=Auto]matches(<A>,[][pos=N]{4})",
 		};
 		PoliqarpPlusTree.debug=true;
 		for (String q : queries) {
@@ -1023,5 +1027,4 @@
 			}
 		}
 	}
-
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/QueryUtils.java b/src/main/java/de/ids_mannheim/korap/query/serialize/QueryUtils.java
index e0f0c0d..0ef4e95 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/QueryUtils.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/QueryUtils.java
@@ -6,6 +6,7 @@
 import org.apache.commons.lang.StringUtils;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -116,6 +117,14 @@
         return children;
     }
 
+    public static List<ParseTree> getChildren(ParseTree node) {
+        ArrayList<ParseTree> children = new ArrayList<ParseTree>();
+        for (int i = 0; i < node.getChildCount(); i++) {
+                children.add(node.getChild(i));
+        }
+        return children;
+    }
+    
     public static Tree getFirstChildWithCat(Tree node, String nodeCat) {
         for (int i = 0; i < node.getChildCount(); i++) {
             if (getNodeCat(node.getChild(i)).equals(nodeCat)) {
@@ -133,6 +142,24 @@
         }
         return null;
     }
+    
+    /**
+     * Checks whether a node only serves as a container for another node (e.g. in (cq_segment ( cg_seg_occ ...)), the cq_segment node does not contain
+     * any information and only contains the cq_seg_occ node.  
+     * @param node The node to check
+     * @return true iff the node is a container only.
+     */
+    public static boolean isContainerOnly(ParseTree node) {
+    	String[] validNodeNamesArray = "cq_segment sq_segment element empty_segments".split(" ");
+    	List<String> validNodeNames = Arrays.asList(validNodeNamesArray);
+    	List<ParseTree> children = getChildren(node);
+    	for (ParseTree child : children) {
+    		if (validNodeNames.contains(getNodeCat(child))) {
+    			return false;
+    		}
+    	}
+    	return true;
+    }
 
     public static void checkUnbalancedPars(String q) throws QueryException {
         int openingPars = StringUtils.countMatches(q, "(");
diff --git a/src/test/java/PoliqarpPlusTreeTest.java b/src/test/java/PoliqarpPlusTreeTest.java
index 217d621..69d9293 100644
--- a/src/test/java/PoliqarpPlusTreeTest.java
+++ b/src/test/java/PoliqarpPlusTreeTest.java
@@ -550,6 +550,35 @@
 		ppt = new PoliqarpPlusTree("[base=Auto]contains(<s>,[base=Mann])");
 		map = ppt.getRequestMap().get("query").toString();
 		assertEquals(pos4.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		// contains(<s>,[pos=N]*)
+		String pos5 = 
+					"{@type=korap:group, operation=operation:position, frame=frame:contains, operands=[" +
+				  		"{@type=korap:span, key=s}," +
+				  		"{@type=korap:group, " +
+				  			"operands=[{@type=korap:token, wrap={@type=korap:term, key=N, layer=pos, match=match:eq}}" +
+				  			"], operation=operation:repetition, min=0, max=100" +
+				  		"}" +
+				  	"]}";
+		ppt = new PoliqarpPlusTree("contains(<s>,[pos=N]*)");
+		map = ppt.getRequestMap().get("query").toString();
+		assertEquals(pos5.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		
+		// [base=Auto]contains(<s>,[pos=N]*)
+		String pos6 = 
+				"{@type=korap:group, operation=operation:sequence, operands=[" +
+					"{@type=korap:token, wrap={@type=korap:term, key=Auto, layer=lemma, match=match:eq}}," +
+					"{@type=korap:group, operation=operation:position, frame=frame:contains, operands=[" +
+				  		"{@type=korap:span, key=s}," +
+				  		"{@type=korap:group, " +
+				  			"operands=[{@type=korap:token, wrap={@type=korap:term, key=N, layer=pos, match=match:eq}}" +
+				  			"], operation=operation:repetition, min=0, max=100" +
+				  		"}" +
+				  	"]}" +
+				"]}";
+		ppt = new PoliqarpPlusTree("[base=Auto]contains(<s>,[pos=N]*)");
+		map = ppt.getRequestMap().get("query").toString();
+		assertEquals(pos6.replaceAll(" ", ""), map.replaceAll(" ", ""));
 	}
 	
 	@Test