Added QueryBuilder
diff --git a/src/main/java/de/ids_mannheim/korap/query/QueryBuilder.java b/src/main/java/de/ids_mannheim/korap/query/QueryBuilder.java
new file mode 100644
index 0000000..28600d5
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/QueryBuilder.java
@@ -0,0 +1,396 @@
+package de.ids_mannheim.korap.query;
+
+import de.ids_mannheim.korap.KrillQuery;
+import de.ids_mannheim.korap.query.wrap.*;
+import org.apache.lucene.util.automaton.RegExp;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QueryBuilder implements a simple API for wrapping
+ * KrillQuery classes.
+ *
+ * Build complex queries.
+ * <blockquote><pre>
+ *   QueryBuilder qb = new QueryBuilder("tokens");
+ *   SpanQueryWrapper sqw = (SpanQueryWrapper)
+ *     qb.seq(
+ *       qb.empty(),
+ *       qb.seg(
+ *         qb.re("mate/p=N.*"),
+ *         qb.re("opennlp/p=N.*")
+ *       )
+ *     );
+ * </pre></blockquote>
+ *
+ * @author diewald
+ */
+public class QueryBuilder {
+    private String field;
+
+    // Logger
+    private final static Logger log = LoggerFactory.getLogger(KrillQuery.class);
+
+    // This advices the java compiler to ignore all loggings
+    public static final boolean DEBUG = false;
+
+    // <legacy>
+    public static final byte
+        OVERLAP      = SpanWithinQuery.OVERLAP,
+        REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP,
+        WITHIN       = SpanWithinQuery.WITHIN,
+        REAL_WITHIN  = SpanWithinQuery.REAL_WITHIN,
+        ENDSWITH     = SpanWithinQuery.ENDSWITH,
+        STARTSWITH   = SpanWithinQuery.STARTSWITH,
+        MATCH        = SpanWithinQuery.MATCH;
+    // </legacy>
+
+
+    /**
+     * Construct a new QueryBuilder object.
+     */
+    public QueryBuilder (String field) {
+        this.field = field;
+    };
+
+    /**
+     * Create a query object based on a regular expression.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanRegexQueryWrapper re = kq.re(".+?");
+     * </pre></blockquote>
+     *
+     * @param re The regular expession as a string.
+     * @return A {@link SpanRegexQueryWrapper} object.
+     */
+    public SpanRegexQueryWrapper re (String re) {
+        return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, false);
+    };
+
+
+    /**
+     * Create a query object based on a regular expression.
+     *
+     * Supports flags as defined in {@link org.apache.lucene.util.automaton.RegExp}:
+     * <ul>
+     *   <li><tt>RegExp.ALL</tt> - enables all optional regexp syntax</li>
+     *   <li><tt>RegExp.ANYSTRING</tt> - enables anystring (@)</li>
+     *   <li><tt>RegExp.AUTOMATON</tt> - enables named automata (&lt;identifier&gt;)</li>
+     *   <li><tt>RegExp.COMPLEMENT</tt> - enables complement (~)</li>
+     *   <li><tt>RegExp.EMPTY</tt> - enables empty language (#)</li>
+     *   <li><tt>RegExp.INTERSECTION</tt> - enables intersection (&amp;)</li>
+     *   <li><tt>RegExp.INTERVAL</tt> - enables numerical intervals (&lt;n-m&gt;)</li>
+     *   <li><tt>RegExp.NONE</tt> - enables no optional regexp syntax</li>
+     * </ul>
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanRegexQueryWrapper re = kq.re("[Aa]lternatives?", RegExp.NONE);
+     * </pre></blockquote>
+     *
+     * @param re The regular expession as a string.
+     * @param flags The flag for the regular expression.
+     * @return A {@link SpanRegexQueryWrapper} object.
+     */
+    public SpanRegexQueryWrapper re (String re, int flags) {
+        return new SpanRegexQueryWrapper(this.field, re, flags, false);
+    };
+
+
+    /**
+     * Create a query object based on a regular expression.
+     *
+     * Supports flags (see above) and case insensitivity.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanRegexQueryWrapper re = kq.re("alternatives?", RegExp.NONE, true);
+     * </pre></blockquote>
+     *
+     * @param re The regular expession as a string.
+     * @param flags The flag for the regular expression.
+     * @param caseinsensitive A boolean value indicating case insensitivity.
+     * @return A {@link SpanRegexQueryWrapper} object.
+     */
+    public SpanRegexQueryWrapper re (String re, int flags, boolean caseinsensitive) {
+        return new SpanRegexQueryWrapper(this.field, re, flags, caseinsensitive);
+    };
+
+
+    /**
+     * Create a query object based on a regular expression.
+     *
+     * Supports case insensitivity.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanRegexQueryWrapper re = kq.re("alternatives?", true);
+     * </pre></blockquote>
+     *
+     * @param re The regular expession as a string.
+     * @param flags The flag for the regular expression.
+     * @return A {@link SpanRegexQueryWrapper} object.
+     */
+    public SpanRegexQueryWrapper re (String re, boolean caseinsensitive) {
+        return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, caseinsensitive);
+    };
+
+    /**
+     * Create a query object based on a wildcard term.
+     * <tt>*</tt> indicates an optional sequence of arbitrary characters,
+     * <tt>?</tt> indicates a single character,
+     * <tt>\</tt> can be used for escaping.
+     *
+     * @param wc The wildcard term as a string.
+     * @return A {@link SpanWildcardQueryWrapper} object.
+     */
+    public SpanWildcardQueryWrapper wc (String wc) {
+        return new SpanWildcardQueryWrapper(this.field, wc, false);
+    };
+
+    /**
+     * Create a query object based on a wildcard term.
+     * <tt>*</tt> indicates an optional sequence of arbitrary characters,
+     * <tt>?</tt> indicates a single character,
+     * <tt>\</tt> can be used for escaping.
+     *
+     * Supports case insensitivity.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanWildcardQueryWrapper wc = kq.wc("wall*", true);
+     * </pre></blockquote>
+     *
+     * @param wc The wildcard term as a string.
+     * @param caseinsensitive A boolean value indicating case insensitivity.
+     * @return A {@link SpanWildcardQueryWrapper} object.
+     */
+    public SpanWildcardQueryWrapper wc (String wc, boolean caseinsensitive) {
+        return new SpanWildcardQueryWrapper(this.field, wc, caseinsensitive);
+    };
+
+
+    /**
+     * Create a segment query object.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanSegmentQueryWrapper seg = kq.seg();
+     * </pre></blockquote>
+     *
+     * @return A {@link SpanSegmentQueryWrapper} object.
+     */
+    public SpanSegmentQueryWrapper seg () {
+        return new SpanSegmentQueryWrapper(this.field);
+    };
+
+
+    /**
+     * Create a segment query object.
+     * Supports sequences of strings or {@link SpanRegexQueryWrapper},
+     * and {@link SpanAlterQueryWrapper} objects.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanSegmentQueryWrapper seg = kq.seg(
+     *       kq.re("mate/p=.*?"),
+     *       kq.re("opennlp/p=.*?")
+     *   );
+     * </pre></blockquote>
+     *
+     * @param terms[] An array of terms, the segment consists of.
+     * @return A {@link SpanSegmentQueryWrapper} object.
+     */
+    // Sequence of regular expression queries
+    public SpanSegmentQueryWrapper seg (SpanRegexQueryWrapper ... terms) {
+        SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+        for (SpanRegexQueryWrapper t : terms)
+            ssq.with(t);
+        return ssq;
+    };
+
+    // Sequence of alternative queries
+    public SpanSegmentQueryWrapper seg (SpanAlterQueryWrapper ... terms) {
+        SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+        for (SpanAlterQueryWrapper t : terms)
+            ssq.with(t);
+        return ssq;
+    };
+
+    // Sequence of alternative queries
+    public SpanSegmentQueryWrapper seg (String ... terms) {
+        SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+        for (String t : terms)
+            ssq.with(t);
+        return ssq;
+    };
+
+    /**
+     * Create an empty query segment.
+     *
+     * <blockquote><pre>
+     *   KrillQuery kq = new KrillQuery("tokens");
+     *   SpanRepetitionQueryWrapper seg = kq.empty();
+     * </pre></blockquote>
+     */
+    public SpanRepetitionQueryWrapper empty () {
+        return new SpanRepetitionQueryWrapper();
+    };
+
+
+    // TODO: Further JavaDocs
+
+
+    /**
+     * Create a segment alternation query object.
+     * @param terms[] An array of alternative terms.
+     */
+    public SpanAlterQueryWrapper or (SpanQueryWrapper ... terms) {
+        SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+        for (SpanQueryWrapper t : terms)
+            ssaq.or(t);
+        return ssaq;
+    };
+
+
+    public SpanAlterQueryWrapper or (String ... terms) {
+        SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+        for (String t : terms)
+            ssaq.or(t);
+        return ssaq;
+    };
+
+
+    // SpanSegmentSequenceQueries
+    /**
+     * Create a sequence of segments query object.
+     */
+    public SpanSequenceQueryWrapper seq () {
+        return new SpanSequenceQueryWrapper(this.field);
+    };
+
+
+    /**
+     * Create a sequence of segments query object.
+     * @param terms[] An array of segment defining terms.
+     */
+    public SpanSequenceQueryWrapper seq (SpanQueryWrapper ... terms) {
+        SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper(this.field);
+        for (SpanQueryWrapper t : terms)
+            sssq.append(t);
+        return sssq;
+    };
+
+
+    /**
+     * Create a sequence of segments query object.
+     * @param re A SpanSegmentRegexQuery, starting the sequence.
+     */
+    public SpanSequenceQueryWrapper seq (SpanRegexQueryWrapper re) {
+        return new SpanSequenceQueryWrapper(this.field, re);
+    };
+
+
+    public SpanSequenceQueryWrapper seq (Object ... terms) {
+        SpanSequenceQueryWrapper ssq = new SpanSequenceQueryWrapper(this.field);
+        for (Object t : terms) {
+            if (t instanceof SpanQueryWrapper) {
+                ssq.append((SpanQueryWrapper) t);
+            }
+            else if (t instanceof SpanRegexQueryWrapper) {
+                ssq.append((SpanRegexQueryWrapper) t);
+            }
+            else {
+                log.error("{} is not an acceptable parameter for seq()", t.getClass());
+                return ssq;
+            };
+        };
+        return ssq;
+    };
+
+
+    public SpanElementQueryWrapper tag (String element) {
+        return new SpanElementQueryWrapper(this.field, element);
+    };
+
+    /**
+     * Create a wrapping within query object.
+     * @param element A SpanQuery.
+     * @param embedded A SpanQuery that is wrapped in the element.
+     */
+    @Deprecated
+    public SpanWithinQueryWrapper within (SpanQueryWrapper element,
+                                          SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded);
+    };
+    
+    public SpanWithinQueryWrapper contains (SpanQueryWrapper element,
+                                            SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded, WITHIN);
+    };
+
+    public SpanWithinQueryWrapper startswith (SpanQueryWrapper element,
+                                              SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded, STARTSWITH);
+    };
+
+    public SpanWithinQueryWrapper endswith (SpanQueryWrapper element,
+                                            SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded, ENDSWITH);
+    };
+
+    public SpanWithinQueryWrapper overlaps (SpanQueryWrapper element,
+                                            SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded, OVERLAP);
+    }; 
+
+    public SpanWithinQueryWrapper matches (SpanQueryWrapper element,
+                                           SpanQueryWrapper embedded) {
+        return new SpanWithinQueryWrapper(element, embedded, MATCH);
+    }; 
+
+    // Class
+    public SpanClassQueryWrapper _ (byte number, SpanQueryWrapper element) {
+        return new SpanClassQueryWrapper(element, number);
+    };
+
+    public SpanClassQueryWrapper _ (int number, SpanQueryWrapper element) {
+        return new SpanClassQueryWrapper(element, number);
+    };
+
+    public SpanClassQueryWrapper _ (short number, SpanQueryWrapper element) {
+        return new SpanClassQueryWrapper(element, number);
+    };
+
+    public SpanClassQueryWrapper _ (SpanQueryWrapper element) {
+        return new SpanClassQueryWrapper(element);
+    };
+
+    // Focus
+    public SpanFocusQueryWrapper focus (byte number, SpanQueryWrapper element) {
+        return new SpanFocusQueryWrapper(element, number);
+    };
+
+    public SpanFocusQueryWrapper focus (int number, SpanQueryWrapper element) {
+        return new SpanFocusQueryWrapper(element, number);
+    };
+
+    public SpanFocusQueryWrapper focus (short number, SpanQueryWrapper element) {
+        return new SpanFocusQueryWrapper(element, number);
+    };
+
+    public SpanFocusQueryWrapper focus (SpanQueryWrapper element) {
+        return new SpanFocusQueryWrapper(element);
+    };
+
+    // Repetition
+    public SpanRepetitionQueryWrapper repeat (SpanQueryWrapper element, int exact) {
+        return new SpanRepetitionQueryWrapper(element, exact);
+    };
+
+    public SpanRepetitionQueryWrapper repeat (SpanQueryWrapper element, int min, int max) {
+        return new SpanRepetitionQueryWrapper(element, min, max);
+    };
+};