Moved match/* to response/match/*
diff --git a/src/main/java/de/ids_mannheim/korap/response/Match.java b/src/main/java/de/ids_mannheim/korap/response/Match.java
index 521be0b..9bcbc06 100644
--- a/src/main/java/de/ids_mannheim/korap/response/Match.java
+++ b/src/main/java/de/ids_mannheim/korap/response/Match.java
@@ -16,11 +16,11 @@
 import de.ids_mannheim.korap.meta.SearchContext;
 
 import de.ids_mannheim.korap.model.AbstractDocument;
-import de.ids_mannheim.korap.match.HighlightCombinator;
-import de.ids_mannheim.korap.match.HighlightCombinatorElement;
-import de.ids_mannheim.korap.match.Relation;
-import de.ids_mannheim.korap.match.MatchIdentifier;
-import de.ids_mannheim.korap.match.PosIdentifier;
+import de.ids_mannheim.korap.response.match.HighlightCombinator;
+import de.ids_mannheim.korap.response.match.HighlightCombinatorElement;
+import de.ids_mannheim.korap.response.match.Relation;
+import de.ids_mannheim.korap.response.match.MatchIdentifier;
+import de.ids_mannheim.korap.response.match.PosIdentifier;
 import de.ids_mannheim.korap.query.SpanElementQuery;
 
 import org.slf4j.Logger;
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/DocIdentifier.java b/src/main/java/de/ids_mannheim/korap/response/match/DocIdentifier.java
new file mode 100644
index 0000000..8680742
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/DocIdentifier.java
@@ -0,0 +1,26 @@
+package de.ids_mannheim.korap.response.match;
+import java.util.*;
+import java.util.regex.*;
+
+
+public class DocIdentifier {
+    protected String corpusID, docID;
+
+    public String getCorpusID () {
+        return this.corpusID;
+    };
+
+    public void setCorpusID (String id) {
+        if (id != null && !id.contains("!"))
+            this.corpusID = id;
+    };
+
+    public String getDocID () {
+        return this.docID;
+    };
+
+    public void setDocID (String id) {
+        if (id != null && !id.contains("!"))
+            this.docID = id;
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinator.java b/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinator.java
new file mode 100644
index 0000000..adce408
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinator.java
@@ -0,0 +1,185 @@
+package de.ids_mannheim.korap.response.match;
+
+import de.ids_mannheim.korap.response.Match;
+import de.ids_mannheim.korap.response.match.HighlightCombinatorElement;
+import java.util.*;
+import java.io.*;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+  Public class for combining highlighting elements
+*/
+public class HighlightCombinator {
+
+    // Logger (use the Match class)
+    private final static Logger log = LoggerFactory.getLogger(Match.class);
+
+    // This advices the java compiler to ignore all loggings
+    public static final boolean DEBUG = false;
+
+    private LinkedList<HighlightCombinatorElement> combine;
+    private Stack<Integer> balanceStack = new Stack<>();
+    private Stack<Integer> tempStack    = new Stack<>();
+
+    // Empty constructor
+    public HighlightCombinator () {
+        this.combine = new LinkedList<>();
+    };
+
+    // Return the combination list
+    public LinkedList<HighlightCombinatorElement> list () {
+        return this.combine;
+    };
+
+    // get the first element (without removing)
+    public HighlightCombinatorElement getFirst () {
+        return this.combine.getFirst();
+    };
+
+    // get the last element (without removing)
+    public HighlightCombinatorElement getLast () {
+        return this.combine.getLast();
+    };
+
+    // get an element by index (without removing)
+    public HighlightCombinatorElement get (int index) {
+        return this.combine.get(index);
+    };
+
+    // Get the size of the combinator stack
+    public short size () {
+        return (short) this.combine.size();
+    };
+
+    // Add primary data to the stack
+    public void addString (String characters) {
+        this.combine.add(new HighlightCombinatorElement(characters));
+    };
+
+    // Add opening highlight combinator to the stack
+    public void addOpen (int number) {
+        this.combine.add(new HighlightCombinatorElement((byte) 1, number));
+        this.balanceStack.push(number);
+    };
+
+    // Add closing highlight combinator to the stack
+    public void addClose (int number) {
+        HighlightCombinatorElement lastComb;
+
+        // Clean up temporary stack
+        this.tempStack.clear();
+        
+        // Check if there is an opening tag at least
+        if (this.balanceStack.empty()) {
+            if (DEBUG)
+                log.trace("The balance stack is empty");
+            return;
+        };
+
+        // Just some debug information
+        if (DEBUG) {
+            StringBuilder sb = new StringBuilder("Stack for checking with class ");
+            sb.append(number).append(" is ");
+            for (int s : this.balanceStack) {
+                sb.append('[').append(s).append(']');
+            };
+            log.trace(sb.toString());
+        };
+
+        // class number of the last element
+        // It's already ensured the stack is not empty
+        int eold = this.balanceStack.pop();
+        
+        // the closing element is not balanced, i.e. the last element differs
+        while (eold != number) {
+            
+            // Retrieve last combinator on stack
+            lastComb = this.combine.peekLast();
+            
+            if (DEBUG)
+                log.trace("Closing element is unbalanced - {} " +
+                          "!= {} with lastComb {}|{}|{}",
+                          eold,
+                          number,
+                          lastComb.type,
+                          lastComb.number,
+                          lastComb.characters);
+
+            // combinator is opening and the number is not equal to the last
+            // element on the balanceStack
+            if (lastComb.type == 1 && lastComb.number == eold) {
+                
+                // Remove the last element - it's empty and uninteresting!
+                this.combine.removeLast();
+            }
+
+            // combinator is either closing (??) or another opener
+            else {
+
+                if (DEBUG)
+                    log.trace("close element a) {}", eold);
+		
+                // Add a closer for the old element (this has following elements)
+                this.combine.add(new HighlightCombinatorElement((byte) 2, eold, false));
+            };
+
+            // add this element number temporarily on the stack
+            tempStack.push(eold);
+
+            // Check next element
+            eold = this.balanceStack.pop();
+        };
+
+        // Get last combinator on the stack
+        lastComb = this.combine.peekLast();
+
+        if (DEBUG) {
+            log.trace("LastComb: " +
+                      lastComb.type +
+                      '|' +
+                      lastComb.number +
+                      '|' + lastComb.characters +
+                      " for " +
+                      number);
+            log.trace("Stack for checking 2: {}|{}|{}|{}",
+                      lastComb.type,
+                      lastComb.number,
+                      lastComb.characters,
+                      number);
+        };
+        
+        if (lastComb.type == 1 && lastComb.number == number) {
+            while (lastComb.type == 1 && lastComb.number == number) {
+                // Remove the damn thing - It's empty and uninteresting!
+                this.combine.removeLast();
+                lastComb = this.combine.peekLast();
+            };
+        }
+        else {
+            if (DEBUG)
+                log.trace("close element b) {}", number);
+	    
+            // Add a closer
+            this.combine.add(new HighlightCombinatorElement((byte) 2, number));
+        };
+
+        // Fetch everything from the tempstack and reopen it
+        for (int e : tempStack) {
+            if (DEBUG)
+                log.trace("Reopen element {}", e);
+            combine.add(new HighlightCombinatorElement((byte) 1, e));
+            balanceStack.push(e);
+        };
+    };
+
+    // Get all combined elements as a string
+    public String toString () {
+        StringBuilder sb = new StringBuilder();
+        for (HighlightCombinatorElement e : combine) {
+            sb.append(e.toString()).append("\n");
+        };
+        return sb.toString();
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinatorElement.java b/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinatorElement.java
new file mode 100644
index 0000000..ab67ed5
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/HighlightCombinatorElement.java
@@ -0,0 +1,158 @@
+package de.ids_mannheim.korap.response.match;
+
+import org.apache.lucene.util.FixedBitSet;
+import de.ids_mannheim.korap.response.Match;
+import de.ids_mannheim.korap.response.match.Relation;
+import static de.ids_mannheim.korap.util.KorapString.*;
+import java.util.*;
+import java.io.*;
+
+/*
+  Class for elements with highlighting information
+*/
+public class HighlightCombinatorElement {
+
+    // Type 0: Textual data
+    // Type 1: Opening
+    // Type 2: Closing
+    public byte type;
+
+    public int number = 0;
+
+    public String characters;
+    public boolean terminal = true;
+
+    // Constructor for highlighting elements
+    public HighlightCombinatorElement (byte type, int number) {
+        this.type = type;
+        this.number = number;
+    };
+
+    // Constructor for highlighting elements,
+    // that may not be terminal, i.e. they were closed and will
+    // be reopened for overlapping issues.
+    public HighlightCombinatorElement (byte type, int number, boolean terminal) {
+        this.type     = type;
+        this.number   = number;
+        this.terminal = terminal;
+    };
+
+    // Constructor for textual data
+    public HighlightCombinatorElement (String characters) {
+        this.type = (byte) 0;
+        this.characters = characters;
+    };
+
+    // Return html fragment for this combinator element
+    public String toHTML (Match match, FixedBitSet level, byte[] levelCache) {	    
+        // Opening
+        if (this.type == 1) {
+            StringBuilder sb = new StringBuilder();
+            if (this.number == -1) {
+                sb.append("<mark>");
+            }
+
+            else if (this.number < -1) {
+                sb.append("<span xml:id=\"")
+                    .append(match.getPosID(match.getClassID(this.number)))
+                    .append("\">");
+            }
+            
+            else if (this.number >= 256) {
+                sb.append("<span ");
+                if (this.number < 2048) {
+                    sb.append("title=\"")
+                        .append(match.getAnnotationID(this.number))
+                        .append('"');
+                }
+                else {
+                    Relation rel = match.getRelationID(this.number);
+                    sb.append("xlink:title=\"")
+                        .append(rel.annotation)
+                        .append("\" xlink:type=\"simple\" xlink:href=\"#")
+                        .append(match.getPosID(rel.ref))
+                        .append('"');
+                };
+                sb.append('>');
+            }
+
+            // Highlight - < 256
+            else {
+                // Get the first free level slot
+                byte pos;
+                if (levelCache[this.number] != '\0') {
+                    pos = levelCache[this.number];
+                }
+                else {
+                    pos = (byte) level.nextSetBit(0);
+                    level.clear(pos);
+                    levelCache[this.number] = pos;
+                };
+                sb.append("<mark class=\"class-")
+                    .append(this.number)
+                    .append(" level-")
+                    .append(pos)
+                    .append("\">");
+            };
+            return sb.toString();
+        }
+        // Closing
+        else if (this.type == 2) {
+            if (this.number < -1 || this.number >= 256)
+                return "</span>";
+           
+            if (this.number == -1)
+                return "</mark>";
+         
+            if (this.terminal)
+                level.set((int) levelCache[this.number]);
+            return "</mark>";
+	};
+
+	// HTML encode primary data
+	return escapeHTML(this.characters);
+    };
+
+    // Return bracket fragment for this combinator element
+    public String toBrackets (Match match) {
+	if (this.type == 1) {
+	    StringBuilder sb = new StringBuilder();
+	    
+	    // Match
+	    if (this.number == -1) {
+		sb.append("[");
+	    }
+
+	    // Identifier
+	    else if (this.number < -1) {
+		sb.append("{#");
+		sb.append(match.getClassID(this.number));
+		sb.append(':');
+	    }
+
+	    // Highlight, Relation, Span
+	    else {
+		sb.append("{");
+		if (this.number >= 256) {
+		    if (this.number < 2048)
+			sb.append(match.getAnnotationID(this.number));
+		    else {
+			Relation rel = match.getRelationID(this.number);
+			sb.append(rel.annotation);
+			sb.append('>').append(rel.ref);
+		    };
+		    sb.append(':');
+		}
+		else if (this.number != 0)
+		    sb.append(this.number).append(':');
+	    };
+	    return sb.toString();
+	}
+	else if (this.type == 2) {
+	    if (this.number == -1)
+		return "]";
+	    return "}";
+	};
+	return this.characters;
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/MatchIdentifier.java b/src/main/java/de/ids_mannheim/korap/response/match/MatchIdentifier.java
new file mode 100644
index 0000000..5b954d6
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/MatchIdentifier.java
@@ -0,0 +1,97 @@
+package de.ids_mannheim.korap.response.match;
+import java.util.*;
+import java.util.regex.*;
+
+public class MatchIdentifier extends DocIdentifier {
+    private int startPos, endPos = -1;
+
+    private ArrayList<int[]> pos = new ArrayList<>(8);
+
+    Pattern idRegex = Pattern.compile(
+		        "^match-(?:([^!]+?)!)?" +
+			"([^!]+)-p([0-9]+)-([0-9]+)" +
+			"((?:\\(-?[0-9]+\\)-?[0-9]+--?[0-9]+)*)" +
+			"(?:c.+?)?$");
+    Pattern posRegex = Pattern.compile(
+		        "\\(([0-9]+)\\)([0-9]+)-([0-9]+)");
+
+    public MatchIdentifier () {};
+    
+    public MatchIdentifier (String id) {
+        Matcher matcher = idRegex.matcher(id);
+        if (matcher.matches()) {
+            this.setCorpusID(matcher.group(1));
+            this.setDocID(matcher.group(2));
+            this.setStartPos(Integer.parseInt(matcher.group(3)));
+            this.setEndPos(Integer.parseInt(matcher.group(4)));
+
+            if (matcher.group(5) != null) {
+                matcher = posRegex.matcher(matcher.group(5));
+                while (matcher.find()) {
+                    this.addPos(
+                        Integer.parseInt(matcher.group(2)),
+                        Integer.parseInt(matcher.group(3)),
+                        Integer.parseInt(matcher.group(1))
+                    );
+                };
+            };
+        };
+    };
+
+    public int getStartPos () {
+        return this.startPos;
+    };
+
+    public void setStartPos (int pos) {
+        if (pos >= 0)
+            this.startPos = pos;
+    };
+
+    public int getEndPos () {
+        return this.endPos;
+    };
+
+    public void setEndPos (int pos) {
+        if (pos >= 0)
+            this.endPos = pos;
+    };
+
+    public void addPos(int start, int end, int number) {
+        if (start >= 0 && end >= 0 && number >= 0)
+            this.pos.add(new int[]{start, end, number});
+    };
+
+    public ArrayList<int[]> getPos () {
+        return this.pos;
+    };
+
+    public String toString () {
+        if (this.docID == null) return null;
+
+        StringBuilder sb = new StringBuilder("match-");
+
+        // Get prefix string corpus/doc
+        if (this.corpusID != null)
+            sb.append(this.corpusID).append('!');
+
+        sb.append(this.docID);
+
+        sb.append('-');
+        sb.append(this.getPositionString());	
+        return sb.toString();
+    };
+
+
+    public String getPositionString () {
+        StringBuilder sb = new StringBuilder();
+        sb.append('p').append(this.startPos).append('-').append(this.endPos);
+
+        // Get Position information
+        for (int[] i : this.pos) {
+            sb.append('(').append(i[2]).append(')');
+            sb.append(i[0]).append('-').append(i[1]);
+        };
+        
+        return sb.toString();
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/PosIdentifier.java b/src/main/java/de/ids_mannheim/korap/response/match/PosIdentifier.java
new file mode 100644
index 0000000..8606aa6
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/PosIdentifier.java
@@ -0,0 +1,34 @@
+package de.ids_mannheim.korap.response.match;
+import java.util.*;
+
+public class PosIdentifier extends DocIdentifier {
+    private int pos;
+
+    public PosIdentifier () {};
+
+    public void setPos (int pos) {
+        if (pos >= 0)
+            this.pos = pos;
+    };
+
+    public int getPos () {
+        return this.pos;
+    };
+
+    public String toString () {
+        if (this.docID == null) return null;
+
+        StringBuilder sb = new StringBuilder("word-");
+
+        // Get prefix string corpus/doc
+        if (this.corpusID != null) {
+            sb.append(this.corpusID).append('!');
+        };
+        sb.append(this.docID);
+
+        sb.append("-p");
+        sb.append(this.pos);
+
+        return sb.toString();
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/match/Relation.java b/src/main/java/de/ids_mannheim/korap/response/match/Relation.java
new file mode 100644
index 0000000..1587ed3
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/match/Relation.java
@@ -0,0 +1,13 @@
+package de.ids_mannheim.korap.response.match;
+
+/**
+ * Class for relational highlights.
+ */   
+public class Relation {
+    public int ref;
+    public String annotation;
+    public Relation (String annotation, int ref) {
+        this.annotation = annotation;
+        this.ref = ref;
+    };
+};