Refactored new collection builder

Change-Id: Ib247d44ba61bc1bbce2ccbd90046a5ea4465d1ae
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 e4207a0..06bafd4 100644
--- a/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java
+++ b/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilderNew.java
@@ -15,180 +15,217 @@
 
 import de.ids_mannheim.korap.KrillCollection;
 
-
-
 public class CollectionBuilderNew {
-    // private BooleanFilter filter;
-    public boolean isNegative = true;
-    public boolean isOptional = false;
-    private ArrayList<CollectionBuilderNew> operands;
-    private Filter filter;
 
     // Logger
-    private final static Logger log = LoggerFactory
-            .getLogger(KrillCollection.class);
+    private final static Logger log = LoggerFactory.getLogger(KrillCollection.class);
 
     // This advices the java compiler to ignore all loggings
     public static final boolean DEBUG = false;
 
-    public boolean isNegative () {
-        return this.isNegative;
+    public CollectionBuilderInterface term (String field, String term) {
+        return new CollectionBuilderTerm(field, term);
     };
 
-    public boolean isOptional () {
-        return this.isOptional;
+    public CollectionBuilderInterface re (String field, String term) {
+        return new CollectionBuilderTerm(field, term, true);
     };
 
-    public CollectionBuilderNew () {
-        // filter = new BooleanFilter();
-    };
-
-    public CollectionBuilderNew create () {
-        return new CollectionBuilderNew();
-    };
-
-    // Filter filter
-    public CollectionBuilderNew or (CollectionBuilderNew cb) {
-        this.isNegative = false;
-        cb.isNegative = false;
-        cb.isOptional = true;
-        if (this.operands == null)
-            this.operands = new ArrayList<CollectionBuilderNew>(3);
-        this.operands.add(cb);
-        return this;
-    };
-
-    public CollectionBuilderNew and (CollectionBuilderNew cb) {
-        this.isNegative = false;
-        cb.isNegative = false;
-        cb.isOptional = false;
-        if (this.operands == null)
-            this.operands = new ArrayList<CollectionBuilderNew>(3);
-        this.operands.add(cb);
-        return this;
-    };
-
-    public CollectionBuilderNew andNot (CollectionBuilderNew cb) {
-        cb.isOptional = false;
-        cb.isNegative = true;
-        if (this.operands == null)
-            this.operands = new ArrayList<CollectionBuilderNew>(3);
-        this.operands.add(cb);
-        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) {
+    public CollectionBuilderInterface since (String field, String date) {
         int since = new KrillDate(date).floor();
 
         if (since == 0 || since == KrillDate.BEGINNING)
             return null;
 
-        this.filter.add(
-            NumericRangeFilter.newIntRange(field, since, KrillDate.END, true, true),
-            BooleanClause.Occur.MUST
-        );
-
-        return this;
+        return new CollectionBuilderRange(field, since, KrillDate.END);
     };
 
-    public CollectionBuilderNew till (String field, String date) {
+    public CollectionBuilderInterface till (String field, String date) {
         try {
             int till = new KrillDate(date).ceil();
             if (till == 0 || till == KrillDate.END)
-                return this;
+                return null;
 
-            this.filter.add(
-                NumericRangeFilter.newIntRange(field,
-                KrillDate.BEGINNING, till, true, true),
-                BooleanClause.Occur.MUST);
+            return new CollectionBuilderRange(field, KrillDate.BEGINNING, till);
         }
         catch (NumberFormatException e) {
             log.warn("Parameter of till(date) is invalid");
         };
-        return this;
+        return null;
     };
 
-
-    public CollectionBuilderNew date (String field, String date) {
+    public CollectionBuilderInterface date (String field, String date) {
         KrillDate dateDF = new KrillDate(date);
 
         if (dateDF.year == 0)
-            return this;
+            return null;
 
         if (dateDF.day == 0 || dateDF.month == 0) {
             int begin = dateDF.floor();
             int end = dateDF.ceil();
 
             if (end == 0
-                    || (begin == KrillDate.BEGINNING && end == KrillDate.END))
-                return this;
+                || (begin == KrillDate.BEGINNING && end == KrillDate.END))
+                return null;
 
-            this.filter.add(NumericRangeFilter.newIntRange(field, begin, end,
-                    true, true), BooleanClause.Occur.MUST);
+            return new CollectionBuilderRange(field, begin, end);
+        };
+        return new CollectionBuilderTerm(field, dateDF.toString());
+    };
+
+
+    public CollectionBuilderGroup andGroup (CollectionBuilderInterface cb) {
+        return new CollectionBuilderGroup(false).with(cb);
+    };
+
+    public CollectionBuilderGroup orGroup (CollectionBuilderInterface cb) {
+        return new CollectionBuilderGroup(true).with(cb);
+    };
+
+    public interface CollectionBuilderInterface {
+        public String toString ();
+        public Filter toFilter ();
+        public boolean isNegative ();
+        public CollectionBuilderInterface not ();
+    };
+
+    public class CollectionBuilderTerm implements CollectionBuilderInterface {
+        private boolean isNegative = false;
+        private boolean regex = false;
+        private String field;
+        private String term;
+
+        public CollectionBuilderTerm (String field, String term) {
+            this.field = field;
+            this.term = term;
+        };
+
+        public CollectionBuilderTerm (String field, String term, boolean regex) {
+            this.field = field;
+            this.term = term;
+            this.regex = regex;
+        };
+
+        public Filter toFilter () {
+            // Regular expression
+            if (this.regex)
+                return new QueryWrapperFilter(
+                    new RegexpQuery(new Term(this.field, this.term))
+                );
+            
+            // Simple term
+            return new TermsFilter(new Term(this.field, this.term));
+        };
+
+        public String toString () {
+            return this.toFilter().toString();
+        };
+
+        public boolean isNegative () {
+            return this.isNegative;
+        };
+
+
+        public CollectionBuilderInterface not () {
+            this.isNegative = true;
+            return this;
+        };
+    };
+
+    public class CollectionBuilderGroup implements CollectionBuilderInterface {
+        private boolean isOptional = false;
+        private boolean isNegative = true;
+
+        public boolean isNegative () {
+            return this.isNegative;
+        };
+
+        public boolean isOptional () {
+            return this.isOptional;
+        };
+
+
+        private ArrayList<CollectionBuilderInterface> operands;
+
+        public CollectionBuilderGroup (boolean optional) {
+            this.isOptional = optional;
+            this.operands = new ArrayList<CollectionBuilderInterface>(3);
+        };
+
+        public CollectionBuilderGroup with (CollectionBuilderInterface cb) {
+            if (!cb.isNegative())
+                this.isNegative = false;
+            this.operands.add(cb);
             return this;
         };
 
-        this.and(this.term(field, dateDF.toString()));
-        return this;
-    };
-    */
+        public Filter toFilter () {
 
-    public CollectionBuilderNew re (String field, String regex) {
-        CollectionBuilderNew cb = new CollectionBuilderNew();
-        cb.filter = new QueryWrapperFilter(new RegexpQuery(new Term(field, regex)));
-        return cb;
-    };
+            if (this.operands == null || this.operands.isEmpty())
+                return null;
 
-    public CollectionBuilderNew term (String field, String term) {
-        CollectionBuilderNew cb = new CollectionBuilderNew();
-        cb.filter = new TermsFilter(new Term(field, term));
-        return cb;
-    };
+            if (this.operands.size() == 1)
+                return this.operands.get(0).toFilter();
 
-    public Filter toFilter () {
-        if (this.filter != null) {
-            return this.filter;
+            BooleanFilter bool = new BooleanFilter();
+
+            Iterator<CollectionBuilderInterface> i = this.operands.iterator();
+            while (i.hasNext()) {
+                CollectionBuilderInterface cb = i.next();
+                if (cb.isNegative()) {
+                    bool.add(cb.toFilter(), BooleanClause.Occur.MUST_NOT);
+                }
+                else if (this.isOptional()) {
+                    bool.add(cb.toFilter(), BooleanClause.Occur.SHOULD);
+                }
+                else {
+                    bool.add(cb.toFilter(), BooleanClause.Occur.MUST);
+                }
+            };
+
+            return bool;
         };
 
-        if (this.operands == null || this.operands.isEmpty())
-            return null;
-
-        BooleanFilter bool = new BooleanFilter();
-
-        if (this.operands.size() == 1)
-            return this.operands.get(0).toFilter();
-
-        Iterator<CollectionBuilderNew> i = this.operands.iterator();
-        while (i.hasNext()) {
-            CollectionBuilderNew cb = i.next();
-            if (cb.isNegative()) {
-                bool.add(cb.toFilter(), BooleanClause.Occur.MUST_NOT);
-            }
-            else if (cb.isOptional()) {
-                bool.add(cb.toFilter(), BooleanClause.Occur.SHOULD);
-            }
-            else {
-                bool.add(cb.toFilter(), BooleanClause.Occur.MUST);
-            }
+        public String toString () {
+            return this.toFilter().toString();
         };
 
-        return bool;
+        public CollectionBuilderInterface not () {
+            this.isNegative = true;
+            return this;
+        };
     };
 
-    public String toString () {
-        Filter filter = this.toFilter();
-        if (filter == null)
-            return "";
-        return filter.toString();
+    public class CollectionBuilderRange implements CollectionBuilderInterface {
+        private boolean isNegative = false;
+        private String field;
+        private int start, end;
+
+        public CollectionBuilderRange (String field, int start, int end) {
+            this.field = field;
+            this.start = start;
+            this.end = end;
+        };
+
+        public boolean isNegative () {
+            return this.isNegative;
+        };
+
+        public String toString () {
+            return this.toFilter().toString();
+        };
+
+        public Filter toFilter () {
+            return NumericRangeFilter.newIntRange(this.field,
+                                                  this.start,
+                                                  this.end,
+                                                  true,
+                                                  true);
+        };
+
+        public CollectionBuilderInterface not () {
+            this.isNegative = true;
+            return this;
+        };
     };
 };
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 4f3e8ce..a2e9b6b 100644
--- a/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestKrillCollectionNew.java
@@ -16,9 +16,10 @@
 public class TestKrillCollectionNew {
 
     @Test
-    public void builderConstruction () throws IOException {
+    public void builderTerm () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        assertEquals("", kc.toString());
+        assertEquals("author:tree",
+                     kc.term("author", "tree").toString());
     };
 
     @Test
@@ -29,105 +30,115 @@
     };
 
     @Test
-    public void builderTerm () throws IOException {
+    public void builderDate () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        assertEquals("author:tree",
-                     kc.term("author", "tree").toString());
+        assertEquals("pubDate:[20050000 TO 20059999]",
+                     kc.date("pubDate", "2005").toString());
     };
 
     @Test
+    public void builderSince () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        assertEquals("pubDate:[20050000 TO 99999999]",
+                     kc.since("pubDate", "2005").toString());
+    };
+
+
+    @Test
+    public void builderTill () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        assertEquals("pubDate:[0 TO 20059999]",
+                     kc.till("pubDate", "2005").toString());
+    };
+
+
+    @Test
     public void builderAndSimple () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.and(kc.term("author", "tree"));
-        assertEquals("author:tree", kc.toString());
-    };
-
-    @Test
-    public void builderAndCombined () throws IOException {
-        CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.and(kc.term("author", "tree")).and(kc.term("title", "name"));
-        assertEquals("BooleanFilter(+author:tree +title:name)", kc.toString());
-    };
-
-    @Test
-    public void builderAndNestedSimple () throws IOException {
-        CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.and(kc.create().and(kc.term("author", "tree")).and(kc.term("title", "name")));
-        assertEquals("BooleanFilter(+author:tree +title:name)", kc.toString());
+        assertEquals("author:tree", kc.andGroup(kc.term("author", "tree")).toString());
     };
 
     @Test
     public void builderOrSimple () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.or(kc.term("author", "tree"));
-        assertEquals("author:tree", kc.toString());
+        assertEquals("author:tree", kc.orGroup(kc.term("author", "tree")).toString());
+    };
+
+    @Test
+    public void builderAndCombined () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        assertEquals("BooleanFilter(+author:tree +title:name)",
+                     kc.andGroup(kc.term("author", "tree"))
+                     .with(kc.term("title", "name")).toString());
+    };
+
+    @Test
+    public void builderAndNestedSimple () throws IOException {
+        CollectionBuilderNew kc = new CollectionBuilderNew();
+        assertEquals("BooleanFilter(+author:tree +title:name)",
+                     kc.andGroup(kc.andGroup(kc.term("author", "tree")).with(kc.term("title", "name"))).toString());
     };
 
 
     @Test
     public void builderOrCombined () throws IOException {
         CollectionBuilderNew kc = new CollectionBuilderNew();
-        kc.or(kc.term("author", "tree")).or(kc.term("title", "name"));
-        assertEquals("BooleanFilter(author:tree title:name)", kc.toString());
+        assertEquals("BooleanFilter(author:tree title:name)",
+                     kc.orGroup(kc.term("author", "tree"))
+                     .with(kc.term("title", "name")).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());
+        assertEquals("BooleanFilter(author:tree title:name)",
+                     kc.orGroup(kc.orGroup(kc.term("author", "tree"))
+                                .with(kc.term("title", "name"))).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());
+        String g = kc.orGroup(
+              kc.orGroup(kc.term("author", "tree1")).with(kc.term("title", "name1"))
+        ).with(
+              kc.andGroup(kc.term("author", "tree2")).with(kc.term("title", "name2"))
+               ).toString();
+        assertEquals("BooleanFilter(BooleanFilter(author:tree1 title:name1) BooleanFilter(+author:tree2 +title:name2))", g);
     };
 
     @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());
+        CollectionBuilderNew.CollectionBuilderInterface kbi = kc.orGroup(kc.term("author", "tree1")).with(kc.term("title", "name1"));
+        assertEquals(
+                     "BooleanFilter(author:tree1 title:name1)",
+                     kbi.toString());
+        assertFalse(kbi.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());
+        kbi = kc.andGroup(
+              kc.orGroup(kc.term("author", "tree1")).with(kc.term("title", "name1"))
+              ).not();
+        assertEquals("BooleanFilter(author:tree1 title:name1)", kbi.toString());
+        assertTrue(kbi.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());
+        CollectionBuilderNew.CollectionBuilderInterface kbi =
+            kc.term("author", "tree").not();
+        assertEquals("author:tree", kbi.toString());
+        assertTrue(kbi.isNegative());
 
-        kc = kc.create();
-        kc.orNot(kc.term("author", "tree"));
-        assertEquals("author:tree", kc.toString());
-        assertTrue(kc.isNegative());
+        kbi = kc.andGroup(kc.term("author", "tree").not());
+        assertEquals("author:tree", kbi.toString());
+        assertTrue(kbi.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());
-        */
+        kbi = kc.orGroup(kc.term("author", "tree").not());
+        assertEquals("author:tree", kbi.toString());
+        assertTrue(kbi.isNegative());
     };
 };