Rethinking negation in collections

Change-Id: I5ba1f171e2b87b984bbef7508ae0e1ef76dcabed
diff --git a/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java b/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java
index e536e78..e4207a0 100644
--- a/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java
+++ b/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java
@@ -43,6 +43,10 @@
         // filter = new BooleanFilter();
     };
 
+    public CollectionBuilderNew create () {
+        return new CollectionBuilderNew();
+    };
+
     // Filter filter
     public CollectionBuilderNew or (CollectionBuilderNew cb) {
         this.isNegative = false;
@@ -64,7 +68,7 @@
         return this;
     };
 
-    public CollectionBuilderNew not (CollectionBuilderNew cb) {
+    public CollectionBuilderNew andNot (CollectionBuilderNew cb) {
         cb.isOptional = false;
         cb.isNegative = true;
         if (this.operands == null)
@@ -73,6 +77,15 @@
         return this;
     };
 
+    public CollectionBuilderNew orNot (CollectionBuilderNew cb) {
+        cb.isNegative = true;
+        cb.isOptional = true;
+        if (this.operands == null)
+            this.operands = new ArrayList<CollectionBuilderNew>(3);
+        this.operands.add(cb);
+        return this;
+    };
+
     /*
     public CollectionBuilderNew since (String field, String date) {
         int since = new KrillDate(date).floor();
diff --git a/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java b/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java
index d0beb34..4f3e8ce 100644
--- a/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java
@@ -52,7 +52,7 @@
     @Test
     public void builderAndNestedSimple () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.and(new CollectionBuilderNew().and(kc.term("author", "tree")).and(kc.term("title", "name")));
+        kc.and(kc.create().and(kc.term("author", "tree")).and(kc.term("title", "name")));
         assertEquals("BooleanFilter(+author:tree +title:name)", kc.toString());
     };
 
@@ -71,4 +71,63 @@
         assertEquals("BooleanFilter(author:tree title:name)", kc.toString());
     };
 
+    @Test
+    public void builderOrNestedSimple () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        kc.or(kc.create().or(kc.term("author", "tree")).or(kc.term("title", "name")));
+        assertEquals("BooleanFilter(author:tree title:name)", kc.toString());
+    };
+
+    @Test
+    public void builderGroups () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        kc.or(
+              kc.create().or(kc.term("author", "tree1")).or(kc.term("title", "name1"))
+        ).or(
+              kc.create().and(kc.term("author", "tree2")).and(kc.term("title", "name2"))
+        );
+        assertEquals("BooleanFilter(BooleanFilter(author:tree1 title:name1) BooleanFilter(+author:tree2 +title:name2))", kc.toString());
+    };
+
+    @Test
+    public void builderNegationRoot () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        kc.or(kc.term("author", "tree1")).or(kc.term("title", "name1"));
+        assertEquals("BooleanFilter(author:tree1 title:name1)", kc.toString());
+        assertFalse(kc.isNegative());
+
+        kc = new CollectionBuilderNew();
+        kc.andNot(
+              kc.create().or(kc.term("author", "tree1")).or(kc.term("title", "name1"))
+        );
+        assertEquals("BooleanFilter(author:tree1 title:name1)", kc.toString());
+        assertTrue(kc.isNegative());
+    };
+
+    @Test
+    public void builderNegation () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        kc.andNot(kc.term("author", "tree"));
+        assertEquals("author:tree", kc.toString());
+        assertTrue(kc.isNegative());
+
+        kc = kc.create();
+        kc.orNot(kc.term("author", "tree"));
+        assertEquals("author:tree", kc.toString());
+        assertTrue(kc.isNegative());
+
+        /*
+        kc = kc.create();
+        // and-group of nots!
+        // Todo: Use orNot!!!
+        kc.not(kc.term("author", "tree")).not(kc.term("title", "name1"));
+        assertEquals("BooleanFilter(+author:tree +title:name1)", kc.toString());
+        assertTrue(kc.isNegative());
+
+        kc = kc.create();
+        kc.not(kc.term("author", "tree")).or(kc.term("title", "name1"));
+        assertEquals("BooleanFilter(-author:tree title:name1)", kc.toString());
+        assertFalse(kc.isNegative());
+        */
+    };
 };