fix for meta data pubdate (since, until, range) and performance improvements
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/MetaQuery.java b/src/main/java/de/ids_mannheim/korap/query/serialize/MetaQuery.java
index aad96b6..adc3d58 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/MetaQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/MetaQuery.java
@@ -33,6 +33,18 @@
         this.types = new MetaTypes();
     }
 
+    /**
+     * temporary solution, since there is no other place for this right now!
+     *
+     * @param request
+     * @param page
+     * @param num
+     * @param cli
+     * @param cri
+     * @param cls
+     * @param crs
+     * @return
+     */
     public static Map addParameters(Map request, int page, int num, String cli, String cri,
                                     int cls, int crs) {
         Map ctx = new LinkedHashMap();
@@ -71,59 +83,67 @@
         return this;
     }
 
-    // map can only have one key, value pair. thus, text class can only be added once. Multiple types are not possible!
-    public MetaQuery addMetaFilter(Map<String, String> queries) {
-        //single is redundant!
-        boolean single = true;
-        boolean multypes = queries.keySet().size() > 1;
-        String def_key = null;
-        if (queries.size() > 1)
-            single = false;
-
+    private List createValue(Multimap<String, String> map) {
         List value = new ArrayList<>();
-        List<String> dates = new ArrayList<>();
-        for (String key : queries.keySet()) {
-            if (!multypes)
-                def_key = key;
-            if (queries.get(key).contains("~") | queries.get(key).contains(">") |
-                    queries.get(key).contains("<")) {
-                dates.add(queries.get(key));
+        String[] dates = new String[3];
+        for (String key : map.keySet()) {
+            if (key.equals("pubDate")) {
+                dates = processDates((List<String>) map.get(key));
                 continue;
             }
 
-            Map term;
-            term = types.createTerm(key, null, queries.get(key).trim(), null);
-            value.add(term);
+            if (map.get(key).size() == 1) {
+                Map term = types.createTerm(key, null, map.get(key).toArray(new String[0])[0], null);
+                value.add(term);
+            } else {
+                List g = new ArrayList();
+                for (String v : map.get(key))
+                    g.add(types.createTerm(null, v, null));
+                Map group = types.createGroup("and", key, g);
+                value.add(group);
+            }
+
         }
 
-        String[] proc = processDates(dates);
         int idx = 3;
-        if (proc[0] != null && proc[0].equals("r")) {
-            Map term1 = types.createTerm(proc[1], "korap:date");
-            Map term2 = types.createTerm(proc[2], "korap:date");
+        if (dates[0] != null && dates[0].equals("r")) {
+            Map term1 = types.createTerm(null, dates[1], "korap:date");
+            Map term2 = types.createTerm(null, dates[2], "korap:date");
             Map group = types.createGroup("between", "pubDate", Arrays.asList(term1, term2));
             value.add(group);
-        } else if (proc[1] != null) {
-            Map term1 = types.createTerm(proc[1], "korap:date");
+        } else if (dates[1] != null) {
+            Map term1 = types.createTerm(null, dates[1], "korap:date");
             Map group = types.createGroup("since", "pubDate", Arrays.asList(term1));
             value.add(group);
-        } else if (proc[2] != null) {
-            Map term1 = types.createTerm(proc[2], "korap:date");
+        } else if (dates[2] != null) {
+            Map term1 = types.createTerm(null, dates[2], "korap:date");
             Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
             value.add(group);
         }
 
 
-        for (int i = idx; i < proc.length; i++) {
-            if (proc[i] != null) {
-                Map term1 = types.createTerm(proc[i], "korap:date");
-                Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
+        for (int i = idx; i < dates.length; i++) {
+            if (dates[i] != null) {
+                Map term1 = types.createTerm(dates[i], "korap:date");
+                Map group = types.createGroup("exact", "pubDate", Arrays.asList(term1));
                 value.add(group);
             }
         }
+        return value;
+    }
 
+    // map can only have one key, value pair. thus, text class can only be added once. Multiple types are not possible!
+    public MetaQuery addMetaFilter(String queries) {
+        Multimap<String, String> m = resEq(queries);
+        boolean multypes = m.keys().size() > 1;
+        String def_key = null;
+
+        if (!multypes)
+            def_key = m.keys().toArray(new String[0])[0];
+
+        List value = this.createValue(m);
         // todo: missing: - takes only one resource, but resources can be chained!
-        if (single)
+        if (m.values().size() == 1)
             Collections.addAll(this.mfil, types.createMetaFilter((Map) value.get(0)));
         else {
             Map group;
@@ -136,59 +156,17 @@
         return this;
     }
 
-    public MetaQuery addMetaExtend(Map<String, String> queries) {
-        //single is redundant!
-        boolean single = true;
-        boolean multypes = queries.keySet().size() > 1;
-
-        //!an extend to a non-existing filter is not possible
-        if (this.mfil.isEmpty())
-            throw new IllegalArgumentException("Extending Query " +
-                    "cannot be added before Filter!");
-
+    public MetaQuery addMetaExtend(String queries) {
+        Multimap<String, String> m = resEq(queries);
+        boolean multypes = m.keys().size() > 1;
         String def_key = null;
-        if (queries.size() > 1)
-            single = false;
 
-        List value = new ArrayList<>();
-        List<String> dates = new ArrayList<>();
-        for (String key : queries.keySet()) {
-            if (!multypes)
-                def_key = key;
-            if (queries.get(key).contains("~") | queries.get(key).contains(">") |
-                    queries.get(key).contains("<")) {
-                dates.add(queries.get(key));
-                continue;
-            }
-            value.add(types.createTerm(key, null, queries.get(key).trim(), null));
-        }
+        if (!multypes)
+            def_key = m.keys().toArray(new String[0])[0];
 
-        String[] proc = processDates(dates);
-        int idx = 3;
-        if (proc[0] != null && proc[0].equals("r")) {
-            Map term1 = types.createTerm(proc[1], "korap:date");
-            Map term2 = types.createTerm(proc[2], "korap:date");
-            Map group = types.createGroup("between", "pubDate", Arrays.asList(term1, term2));
-            value.add(group);
-        } else if (proc[1] != null) {
-            Map term1 = types.createTerm(proc[1], "korap:date");
-            Map group = types.createGroup("since", "pubDate", Arrays.asList(term1));
-            value.add(group);
-        } else if (proc[2] != null) {
-            Map term1 = types.createTerm(proc[2], "korap:date");
-            Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
-            value.add(group);
-        }
-
-        for (int i = idx; i < proc.length; i++) {
-            if (proc[i] != null) {
-                Map term1 = types.createTerm(proc[i], "korap:date");
-                Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
-                value.add(group);
-            }
-        }
+        List value = this.createValue(m);
         // todo: missing: - takes only one resource, but resources can be chained!
-        if (single)
+        if (m.values().size() == 1)
             Collections.addAll(this.mext, types.createMetaExtend((Map) value.get(0)));
         else {
             Map group;
@@ -202,15 +180,11 @@
     }
 
     public MetaQuery addMetaFilter(String attr, String val) {
-        Map y = new HashMap<>();
-        y.put(attr, val);
-        return addMetaFilter(y);
+        return addMetaFilter(attr + ":" + val);
     }
 
     public MetaQuery addMetaExtend(String attr, String val) {
-        Map y = new HashMap<>();
-        y.put(attr, val);
-        return addMetaExtend(y);
+        return addMetaExtend(attr + ":" + val);
     }
 
     private String[] processDates(List<String> dates) {
@@ -226,17 +200,12 @@
             } else if (value.contains(">")) {
                 String[] sp = value.split(">");
                 el[2] = types.formatDate(Long.valueOf(sp[1]), MetaTypes.YMD);
-            } else if (value.contains("~")) {
-                range = true;
-                String[] sp = value.split("~");
-                el[1] = types.formatDate(Long.valueOf(sp[0]), MetaTypes.YMD);
-                el[2] = types.formatDate(Long.valueOf(sp[1]), MetaTypes.YMD);
             } else {
                 el[idx] = types.formatDate(Long.valueOf(value), MetaTypes.YMD);
                 idx++;
             }
         }
-        if (range)
+        if (el[1] != null && el[2] != null)
             el[0] = "r";
         return el;
     }
@@ -266,8 +235,12 @@
      * @return
      */
     public String stringify() {
+        List meta = getMetaOnly();
+        if (meta.isEmpty())
+            return "";
+
         try {
-            return serialzer.writeValueAsString(getMetaOnly());
+            return serialzer.writeValueAsString(meta);
         } catch (JsonProcessingException e) {
             e.printStackTrace();
             return "";
@@ -306,8 +279,13 @@
         }
     }
 
-    private Multimap resEq(String queries) {
-        Multimap qmap = ArrayListMultimap.create();
+    /**
+     * resolves all queries as equal (hierarchy) AND relations
+     * @param queries
+     * @return
+     */
+    private Multimap<String, String> resEq(String queries) {
+        Multimap<String, String> qmap = ArrayListMultimap.create();
         String[] spl = queries.split(" AND ");
         for (String query : spl) {
             String[] q = query.split(":");
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/MetaTypes.java b/src/main/java/de/ids_mannheim/korap/query/serialize/MetaTypes.java
index 405dc4b..59a9376 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/MetaTypes.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/MetaTypes.java
@@ -51,8 +51,12 @@
         return term;
     }
 
-    public Map createTerm(String value, String type) {
-        return createTerm(null, null, value, type);
+    public Map createTerm(String field, String value, String type) {
+        return createTerm(field, null, value, type);
+    }
+
+    public Map createTerm(String field, String value) {
+        return createTerm(field, value,  null);
     }
 
     public Map createResourceFilter(String resource, Map value) {
diff --git a/src/test/java/MetaQuerySerializationTest.java b/src/test/java/MetaQuerySerializationTest.java
index 4c3b355..f0a5392 100644
--- a/src/test/java/MetaQuerySerializationTest.java
+++ b/src/test/java/MetaQuerySerializationTest.java
@@ -4,14 +4,12 @@
 import de.ids_mannheim.korap.query.serialize.JsonGenerator;
 import de.ids_mannheim.korap.query.serialize.MetaQuery;
 import org.joda.time.DateTime;
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
 /**
  * @author hanl
@@ -24,53 +22,62 @@
 
     @Test
     public void test() throws IOException {
-        Map<String, String> j = new HashMap();
-        j.put("author", "Goethe");
-        j.put("pubPlace", "Erfurt");
-        j.put("textClass", "wissenschaft");
-        MetaQuery qu = new MetaQuery().addMetaFilter(j);
-        System.out.println("value reference " + qu.stringify());
-        System.out.println();
+        StringBuffer b = new StringBuffer();
+        b.append("author:Goethe");
+        b.append(" AND ");
+        b.append("pubPlace:Erfurt");
+        b.append(" AND ");
+        b.append("textClass:wissenschaft");
+        MetaQuery qu = new MetaQuery().addMetaFilter(b.toString());
+//        System.out.println("value reference " + qu.stringify());
+//        System.out.println();
     }
 
     @Test
     public void testSingle() throws IOException {
-        Map<String, String> j = new HashMap();
-        j.put("textClass", "wissenschaft");
         MetaQuery query = new MetaQuery().addMetaFilter("textClass", "wissenschaft");
-        System.out.println("------ TEXT SINGLE " + query.stringify());
+//        System.out.println("------ TEXT SINGLE " + query.stringify());
         System.out.println();
     }
 
     @Test
     public void testDates() throws IOException {
-        Map<String, String> queries = new LinkedHashMap<>();
-        queries.put("pubDate", String.valueOf(new DateTime().getMillis()) + "~"
-                + String.valueOf(new DateTime().getMillis() + 2));
-        queries.put("author", "Goethe");
-        MetaQuery query = new MetaQuery().addMetaFilter(queries);
-        System.out.println("value until/since : " + query.stringify());
-        System.out.println();
+        StringBuffer b = new StringBuffer();
+        b.append("pubDate:<" + String.valueOf(new DateTime().getMillis()));
+        b.append(" AND ");
+        b.append("pubDate:>" + String.valueOf(new DateTime().getMillis() + 2));
+        b.append(" AND ");
+        b.append("author:Goethe");
+        MetaQuery query = new MetaQuery().addMetaFilter(b.toString());
+//        System.out.println("value until/since : " + query.stringify());
+        Assert.assertEquals("[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:group\",\"relation\":\"and\",\"operands\":[{\"@type\":\"korap:term\",\"@field\":\"korap:field#author\",\"@value\":\"Goethe\"},{\"@type\":\"korap:group\",\"@field\":\"korap:field#pubDate\",\"relation\":\"between\",\"operands\":[{\"@type\":\"korap:date\",\"@value\":\"2013-12-09\"},{\"@type\":\"korap:date\",\"@value\":\"2013-12-09\"}]}]}}]", query.stringify());
+//        System.out.println();
     }
 
     @Test
     public void testUntil() throws IOException {
-        Map<String, String> queries = new LinkedHashMap<>();
-        queries.put("pubDate", ">" + String.valueOf(new DateTime().getMillis()));
-        queries.put("author", "Hesse");
-        MetaQuery query = new MetaQuery().addMetaFilter(queries);
-        System.out.println("value until : " + query.stringify());
-        System.out.println();
+        StringBuffer b = new StringBuffer();
+        b.append("pubDate:>" + String.valueOf(new DateTime().getMillis()));
+        b.append(" AND ");
+        b.append("author:Hesse");
+        MetaQuery query = new MetaQuery().addMetaFilter(b.toString());
+        System.out.println("Running date check (until) with additional attribute author");
+        Assert.assertEquals("[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:group\",\"relation\":\"and\",\"operands\":[{\"@type\":\"korap:term\",\"@field\":\"korap:field#author\",\"@value\":\"Hesse\"},{\"@type\":\"korap:group\",\"@field\":\"korap:field#pubDate\",\"relation\":\"until\",\"operands\":[{\"@type\":\"korap:date\",\"@value\":\"2013-12-09\"}]}]}}]", query.stringify());
+//        System.out.println("value until : " + query.stringify());
+//        System.out.println();
     }
 
     @Test
     public void testSince() throws IOException {
-        Map<String, String> queries = new LinkedHashMap<>();
-        queries.put("pubDate", "<" + String.valueOf(new DateTime().getMillis()));
-        queries.put("author", "Kafka");
-        MetaQuery query = new MetaQuery().addMetaFilter(queries);
-        System.out.println("value since : " + query.stringify());
-        System.out.println();
+        StringBuffer b = new StringBuffer();
+        b.append("pubDate:<" + String.valueOf(new DateTime().getMillis()));
+        b.append(" AND ");
+        b.append("author:Kafka");
+        MetaQuery query = new MetaQuery().addMetaFilter(b.toString());
+//        System.out.println("value since : " + query.stringify());
+//        System.out.println();
+        System.out.println("Running date check (since) with additional attribute author");
+        Assert.assertEquals("[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:group\",\"relation\":\"and\",\"operands\":[{\"@type\":\"korap:term\",\"@field\":\"korap:field#author\",\"@value\":\"Kafka\"},{\"@type\":\"korap:group\",\"@field\":\"korap:field#pubDate\",\"relation\":\"since\",\"operands\":[{\"@type\":\"korap:date\",\"@value\":\"2013-12-09\"}]}]}}]", query.stringify());
     }
 
     @Test
@@ -109,26 +116,27 @@
 
     @Test
     public void testLists() {
-        Map<String, String> queries = new LinkedHashMap<>();
-        queries.put("pubDate", "<" + String.valueOf(new DateTime().getMillis()));
-        queries.put("author", "Kafka");
-        MetaQuery query = new MetaQuery().addMetaFilter(queries);
-
+        StringBuffer b = new StringBuffer();
+        b.append("pubDate:<" + String.valueOf(new DateTime().getMillis()));
+        b.append(" AND ");
+        b.append("author:Kafka");
+        MetaQuery query = new MetaQuery().addMetaFilter(b.toString());
         query.addMetaExtend("author", "Hesse");
 
-        System.out.println("--- ALL " + query.stringify());
-        System.out.println();
+//        System.out.println("--- ALL " + query.stringify());
+//        System.out.println();
 
     }
 
     @Test
     public void testJSONArray() throws JsonProcessingException {
-        Map<String, String> queries = new LinkedHashMap<>();
-        queries.put("pubDate", "<" + String.valueOf(new DateTime().getMillis()));
-        queries.put("author", "Kafka");
-        MetaQuery q = new MetaQuery().addMetaExtend(queries);
-        System.out.println("array repres " + q.toMeta());
-        System.out.println();
+        StringBuffer b = new StringBuffer();
+        b.append("pubDate:<" + String.valueOf(new DateTime().getMillis()));
+        b.append(" AND ");
+        b.append("author:Kafka");
+        MetaQuery q = new MetaQuery().addMetaExtend(b.toString());
+//        System.out.println("array repres " + q.toMeta());
+//        System.out.println();
     }
 
     @Test
@@ -136,9 +144,9 @@
         MetaQuery q = new MetaQuery().addMetaFilter("corpusID", "A00");
         q.addMetaExtend("corpusID", "A01");
 
-        System.out.println("results stringified " + q.stringify());
-        System.out.println("results to meta" + q.toMeta());
-        System.out.println();
+//        System.out.println("results stringified " + q.stringify());
+//        System.out.println("results to meta" + q.toMeta());
+//        System.out.println();
     }
 
     /**
@@ -152,23 +160,25 @@
         String meta = "[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:term\",\"@field\":\"korap:field#corpusID\",\"@value\":\"WPD\"}}]";
         MetaQuery q = new MetaQuery().addResource(meta);
         org.junit.Assert.assertEquals("String should be empty", "", q.stringify());
-        System.out.println("meta string " + q.toMeta());
-        org.junit.Assert.assertEquals(meta, q.toMeta());
+//        System.out.println("meta string " + q.toMeta());
+        System.out.println("Testing Resource Meta data");
+        org.junit.Assert.assertEquals("{\"meta\":" + meta + "}", q.toMeta());
     }
 
     @Test
     public void testA00() throws IOException {
         MetaQuery q = new MetaQuery().addMetaExtend("corpusID", "A00").addMetaExtend("corpusID", "A01");
-        System.out.println("A meta: " + q.stringify());
-        System.out.println();
+//        System.out.println("A meta: " + q.stringify());
+//        System.out.println();
     }
 
     @Test
-    public void testnewMetaQuery() throws IOException {
+    public void testResources2() throws IOException {
         String meta = "[{\"@type\":\"korap:meta-filter\",\"@value\":{\"@type\":\"korap:term\",\"@field\":\"korap:field#corpusID\",\"@value\":\"WPD\"}}]";
         MetaQuery q = new MetaQuery().addResource(meta);
         q.addMetaFilter("textClass", "wissenschaft");
-        System.out.println("meta string " + q.toMeta());
+//        System.out.println("stringified meta " + q.stringify());
+//        System.out.println("meta string " + q.toMeta());
     }
 
 }