Changed class number policy for relations: source always has class #1
and target #2.

Change-Id: I758739335fbabf5b6743c119d668c22133ee3cd7
diff --git a/src/main/java/de/ids_mannheim/korap/KrillQuery.java b/src/main/java/de/ids_mannheim/korap/KrillQuery.java
index f7fbdbd..c966cc0 100644
--- a/src/main/java/de/ids_mannheim/korap/KrillQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KrillQuery.java
@@ -257,6 +257,9 @@
                     if (number > MAX_CLASS_NUM)
                         throw new QueryException(709,
                                 "Valid class numbers exceeded");
+
+                    this.classNumbers = null;
+
                 }
 
                 // Reference based on spans
@@ -693,9 +696,6 @@
                 throw new QueryException(709, "Valid class numbers exceeded");
             };
 
-            this.classNumbers[0] = (byte) number;
-            this.classNumbers[1] = (byte) 0;
-
             // Serialize operand
             SpanQueryWrapper sqw = this.fromJson(operands.get(0));
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanRelationQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanRelationQuery.java
index cf1c154..8df29b3 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SpanRelationQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanRelationQuery.java
@@ -7,6 +7,7 @@
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
 import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.SpanTermQuery;
 import org.apache.lucene.search.spans.Spans;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.ToStringUtils;
@@ -53,8 +54,7 @@
  * */
 public class SpanRelationQuery extends SimpleSpanQuery {
 
-    private String type;
-
+    private int direction = 0;
 
     /**
      * Constructs a SpanRelationQuery based on the given span query.
@@ -69,6 +69,11 @@
      */
     public SpanRelationQuery (SpanQuery firstClause, boolean collectPayloads) {
         super(firstClause, collectPayloads);
+        SpanTermQuery st = (SpanTermQuery) firstClause;
+        String direction = st.getTerm().text().substring(0, 1);
+        if (direction.equals("<")) {
+            this.direction = 1;
+        }
     }
 
 
@@ -97,4 +102,12 @@
         return sb.toString();
     }
 
+    public int getDirection() {
+        return direction;
+    }
+
+    public void setDirection(int direction) {
+        this.direction = direction;
+    }
+
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
index 853ce2f..f17043d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
@@ -20,14 +20,11 @@
 
 /**
  * Enumeration of spans denoting relations between two
- * tokens/elements. The
- * start and end of a RelationSpan always denote the start and end of
- * the
- * left-side token/element.
+ * tokens/elements. The start and end of a RelationSpan always denote
+ * the start and end of the left-side token/element.
  * 
  * There are 4 types of relations, which is differentiated by the
- * payload length
- * in bytes.
+ * payload length in bytes.
  * <ol>
  * <li>Token to token relation (1 int & 3 short, length: 10)</li>
  * <li>Token to span (2 int & 3 short, length: 14)</li>
@@ -35,29 +32,28 @@
  * <li>Span to Span (3 int & 3 short, length: 18)</li>
  * </ol>
  * Every integer value denotes the start/end position of the
- * start/target of a
- * relation, in this format: (sourceEndPos?, startTargetPos,
- * endTargetPos?). The
- * end position of a token is identical to its start position, and
- * therefore not
- * is saved in a payload.
+ * start/target of a relation, in this format: (sourceEndPos?,
+ * startTargetPos, endTargetPos?). The end position of a token is
+ * identical to its start position, and therefore not is saved in a
+ * payload.
  * 
  * The short values denote the relation id, left id, and right id. The
- * byte in
- * relation #3 is just a dummy to create a different length from the
- * relation
- * #2.
+ * byte in relation #3 is just a dummy to create a different length
+ * from the relation #2.
  * 
  * NOTE: Sorting of the candidate spans can alternatively be done in
- * indexing,
- * instead of here. (first by left positions and then by right
- * positions)
+ * indexing, instead of here. (first by left positions and then by
+ * right positions)
+ * 
+ * The class number of relation source is always 1 and that of
+ * relation target is always 2 regardless of the relation direction.
  * 
  * @author margaretha
  * */
 public class RelationSpans extends RelationBaseSpans {
 
     private int currentDoc, currentPosition;
+    private int direction;
     private TermSpans relationTermSpan;
 
     protected Logger logger = LoggerFactory.getLogger(RelationSpans.class);
@@ -80,6 +76,7 @@
                           Map<Term, TermContext> termContexts)
             throws IOException {
         super(relationSpanQuery, context, acceptDocs, termContexts);
+        direction = relationSpanQuery.getDirection();
         candidateList = new ArrayList<>();
         relationTermSpan = (TermSpans) firstSpans;
         hasMoreSpans = relationTermSpan.next();
@@ -214,10 +211,18 @@
         if (relationTermSpan.isPayloadAvailable()) {
             payload.addAll(relationTermSpan.getPayload());
         }
-        payload.add(createClassPayload(cs.getLeftStart(), cs.getLeftEnd(),
-                (byte) 1));
-        payload.add(createClassPayload(cs.getRightStart(), cs.getRightEnd(),
-                (byte) 2));
+        if (direction == 0) {
+            payload.add(createClassPayload(cs.getLeftStart(), cs.getLeftEnd(),
+                    (byte) 1));
+            payload.add(createClassPayload(cs.getRightStart(),
+                    cs.getRightEnd(), (byte) 2));
+        }
+        else {
+            payload.add(createClassPayload(cs.getRightStart(),
+                    cs.getRightEnd(), (byte) 1));
+            payload.add(createClassPayload(cs.getLeftStart(), cs.getLeftEnd(),
+                    (byte) 2));
+        }
         cs.setPayloads(payload);
     }
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRelationWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRelationWrapper.java
index 634ade8..17afa22 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRelationWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRelationWrapper.java
@@ -49,31 +49,22 @@
         if (sq == null)
             return null;
 
-        ArrayList<Byte> classNumbers = new ArrayList<Byte>();
-        for (byte c : this.classNumbers) {
-            if (c > 0) {
-                classNumbers.add(c);
-            }
-        }
-
         SpanQuery subq1, subq2;
         if (subQuery1.isEmpty) {
             if (!subQuery2.isEmpty) {
-                // match subquery2
+                // match target
                 subq2 = subQuery2.retrieveNode(this.retrieveNode).toQuery();
                 if (subq2 != null) {
-                    return new SpanFocusQuery(new SpanSegmentQuery(sq, subq2,
-                            true), classNumbers);
+                    return createQuery(new SpanSegmentQuery(sq, subq2, true));
                 }
             }
         }
         else if (subQuery2.isEmpty) {
             if (!subQuery1.isEmpty) {
-                // match subquery1
+                // match source
                 subq1 = subQuery1.retrieveNode(this.retrieveNode).toQuery();
                 if (subq1 != null) {
-                    return new SpanFocusQuery(new SpanSegmentQuery(sq, subq1,
-                            true), classNumbers);
+                    return createQuery(new SpanSegmentQuery(sq, subq1, true));
                 }
             }
         }
@@ -89,11 +80,24 @@
 
             subq2 = subQuery2.retrieveNode(this.retrieveNode).toQuery();
             if (subq2 != null) {
-                return new SpanFocusQuery(
-                        new SpanSegmentQuery(sq, subq2, true), classNumbers);
+                return createQuery(new SpanSegmentQuery(sq, subq2, true));
             }
         }
 
-        return new SpanFocusQuery(sq, classNumbers);
+        return createQuery(sq);
+    }
+
+    private SpanQuery createQuery(SpanQuery sq) {
+        ArrayList<Byte> classNumbers = new ArrayList<Byte>();
+        if (this.classNumbers != null) {
+            for (byte c : this.classNumbers) {
+                if (c > 0) {
+                    classNumbers.add(c);
+                }
+            }
+            return new SpanFocusQuery(sq, classNumbers);
+        }
+        return sq;
+
     }
 }
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
index f151843..e0d6598 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
@@ -522,7 +522,7 @@
         SpanQuery rv = new SpanFocusQuery(new SpanSegmentQuery(
                 new SpanRelationQuery(new SpanTermQuery(new Term("base",
                         "<:dep")), true), new SpanTermWithIdQuery(new Term(
-                        "base", "pos:NN"), true), true), (byte) 2);
+                        "base", "pos:NN"), true), true), (byte) 1);
 
         kr = ki.search(rv, (short) 10);
         assertEquals((long) 3, kr.getTotalResults());
@@ -566,7 +566,7 @@
         SpanFocusQuery rv = new SpanFocusQuery(new SpanSegmentQuery(
                 new SpanRelationQuery(new SpanTermQuery(new Term("base",
                         "<:child-of")), true), new SpanElementQuery("base",
-                        "np"), true), (byte) 2);
+                        "np"), true), (byte) 1);
         rv.setSorted(false);
 
         kr = ki.search(rv, (short) 10);
@@ -602,7 +602,10 @@
         // return all nps whose children are articles
         SpanSegmentQuery rv3 = new SpanSegmentQuery(rv,
                 new SpanTermWithIdQuery(new Term("base", "pos:ART"), true));
-        kr = ki.search(rv3, (short) 10);
+        
+        
+        SpanFocusQuery sf = new SpanFocusQuery(rv3, (byte) 1);
+        kr = ki.search(sf, (short) 10);
 
         assertEquals((long) 2, kr.getTotalResults());
 
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanRelationQueryJSON.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanRelationQueryJSON.java
index be2eb5f..2512d1d 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanRelationQueryJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanRelationQueryJSON.java
@@ -88,7 +88,7 @@
         assertEquals("focus([1,2]tokens:<:mate/d:HEAD)", sq.toString());
     }
 
-
+    @Test
     public void testFocusSource () throws QueryException {
         //
         String filepath = getClass().getResource(
@@ -96,18 +96,18 @@
         SpanQueryWrapper sqwi = getJSONQuery(filepath);
         SpanQuery sq = sqwi.toQuery();
         assertEquals(
-                "focus([1]spanSegment(focus(2: spanSegment(tokens:>:mate/d:HEAD, <tokens:c:s />)), <tokens:c:vp />))",
+                "focus(1: spanSegment(tokens:<:mate/d:HEAD, <tokens:np />))",
                 sq.toString());
     }
 
-
+    @Test
     public void testFocusTarget () throws QueryException {
         String filepath = getClass().getResource(
-                "/queries/relation/match-source.json").getFile();
+                "/queries/relation/focus-target.json").getFile();
         SpanQueryWrapper sqwi = getJSONQuery(filepath);
         SpanQuery sq = sqwi.toQuery();
         assertEquals(
-                "focus([2]spanSegment(tokens:>:mate/d:HEAD, <tokens:c:s />))",
+                "focus(2: spanSegment(tokens:>:mate/d:HEAD, <tokens:s />))",
                 sq.toString());
     }
 }
diff --git a/src/test/resources/queries/relation/focus-source.json b/src/test/resources/queries/relation/focus-source.json
index 8ac35c7..d934a3b 100644
--- a/src/test/resources/queries/relation/focus-source.json
+++ b/src/test/resources/queries/relation/focus-source.json
@@ -1,25 +1,24 @@
 {
     "query": {
-        "@type": "korap:reference",
+        "@type": "koral:reference",
         "operation": "operation:focus",
         "classRef": [1],
         "operands": [{
-            "@type": "korap:group",
+            "@type": "koral:group",
             "operation": "operation:relation",
             "operands": [
                 {
-                    "@type": "korap:span",
-                    "key": "s"
+                    "@type": "koral:token"
                 },
                 {
-                    "@type": "korap:span",
+                    "@type": "koral:span",
                     "key": "np"
                 }
             ],
             "relation": {
-                "@type": "korap:relation",
+                "@type": "koral:relation",
                 "wrap": {
-                    "@type": "korap:term",
+                    "@type": "koral:term",
                     "foundry": "mate",
                     "layer": "d",
                     "key": "HEAD"
diff --git a/src/test/resources/queries/relation/focus-target.json b/src/test/resources/queries/relation/focus-target.json
index ce7ae66..daec972 100644
--- a/src/test/resources/queries/relation/focus-target.json
+++ b/src/test/resources/queries/relation/focus-target.json
@@ -1,24 +1,24 @@
 {
     "query": {
-        "@type": "korap:reference",
+        "@type": "koral:reference",
         "operation": "operation:focus",
         "classRef": [2],
         "operands": [{
-            "@type": "korap:group",
+            "@type": "koral:group",
             "operation": "operation:relation",
             "operands": [
                 {
-                    "@type": "korap:span",
+                    "@type": "koral:span",
                     "key": "s"
                 },
                 {
-                    "@type": "korap:token"
+                    "@type": "koral:token"
                 }
             ],
             "relation": {
-                "@type": "korap:relation",
+                "@type": "koral:relation",
                 "wrap": {
-                    "@type": "korap:term",
+                    "@type": "koral:term",
                     "foundry": "mate",
                     "layer": "d",
                     "key": "HEAD"