blob: c39825a24d1704f2cff6e41849b63eeb44fcef02 [file] [log] [blame]
Nils Diewaldff0f8742015-02-26 20:42:45 +00001package de.ids_mannheim.korap.response.match;
Nils Diewald79f6c4d2014-09-17 17:34:01 +00002
3import org.apache.lucene.util.FixedBitSet;
Nils Diewald392bcf32015-02-26 20:01:17 +00004import de.ids_mannheim.korap.response.Match;
Nils Diewaldff0f8742015-02-26 20:42:45 +00005import de.ids_mannheim.korap.response.match.Relation;
Nils Diewaldc383ed02015-02-26 21:35:22 +00006import static de.ids_mannheim.korap.util.KrillString.*;
Nils Diewald79f6c4d2014-09-17 17:34:01 +00007import java.util.*;
8import java.io.*;
9
Akron47929692017-09-12 14:41:26 +020010import org.slf4j.Logger;
11import org.slf4j.LoggerFactory;
12
Nils Diewald79f6c4d2014-09-17 17:34:01 +000013/*
14 Class for elements with highlighting information
15*/
16public class HighlightCombinatorElement {
17
Akron12cd2582018-02-17 12:58:38 +010018 // Number -1: Match
19 // Number -99998: Context
20 private final static int CONTEXT = -99998;
21
Nils Diewald79f6c4d2014-09-17 17:34:01 +000022 // Type 0: Textual data
23 // Type 1: Opening
24 // Type 2: Closing
Akrond4b19332017-02-15 18:36:24 +010025 // Type 3: Empty
Nils Diewald79f6c4d2014-09-17 17:34:01 +000026 public byte type;
27
28 public int number = 0;
29
30 public String characters;
31 public boolean terminal = true;
32
Akron47929692017-09-12 14:41:26 +020033 // Logger
34 private final static Logger log = LoggerFactory.getLogger(Match.class);
35
36 // This advices the java compiler to ignore all loggings
Akron04f00952018-03-06 18:56:54 +010037 public static final boolean DEBUG = false;
Nils Diewaldbb33da22015-03-04 16:24:25 +000038
Nils Diewald79f6c4d2014-09-17 17:34:01 +000039 // Constructor for highlighting elements
40 public HighlightCombinatorElement (byte type, int number) {
Nils Diewaldff0f8742015-02-26 20:42:45 +000041 this.type = type;
42 this.number = number;
Nils Diewald79f6c4d2014-09-17 17:34:01 +000043 };
44
Nils Diewaldbb33da22015-03-04 16:24:25 +000045
Nils Diewald79f6c4d2014-09-17 17:34:01 +000046 // Constructor for highlighting elements,
47 // that may not be terminal, i.e. they were closed and will
48 // be reopened for overlapping issues.
Eliza Margaretha6f989202016-10-14 21:48:29 +020049 public HighlightCombinatorElement (byte type, int number,
50 boolean terminal) {
Nils Diewaldbb33da22015-03-04 16:24:25 +000051 this.type = type;
52 this.number = number;
Nils Diewaldff0f8742015-02-26 20:42:45 +000053 this.terminal = terminal;
Nils Diewald79f6c4d2014-09-17 17:34:01 +000054 };
55
Nils Diewaldbb33da22015-03-04 16:24:25 +000056
Nils Diewald79f6c4d2014-09-17 17:34:01 +000057 // Constructor for textual data
58 public HighlightCombinatorElement (String characters) {
Nils Diewaldff0f8742015-02-26 20:42:45 +000059 this.type = (byte) 0;
60 this.characters = characters;
Nils Diewald79f6c4d2014-09-17 17:34:01 +000061 };
62
Nils Diewaldbb33da22015-03-04 16:24:25 +000063
Nils Diewald79f6c4d2014-09-17 17:34:01 +000064 // Return html fragment for this combinator element
Akron12cd2582018-02-17 12:58:38 +010065 public String toHTML (Match match, FixedBitSet level, byte[] levelCache, HashSet joins) {
Akrond4b19332017-02-15 18:36:24 +010066
Nils Diewalddcd5ab12015-02-20 02:59:09 +000067 // Opening
68 if (this.type == 1) {
69 StringBuilder sb = new StringBuilder();
Akronf05fde62016-08-03 23:46:17 +020070
Akron08f4ceb2016-08-03 23:53:32 +020071 // This is the surrounding match mark
Nils Diewalddcd5ab12015-02-20 02:59:09 +000072 if (this.number == -1) {
73 sb.append("<mark>");
74 }
Nils Diewald79f6c4d2014-09-17 17:34:01 +000075
Akron12cd2582018-02-17 12:58:38 +010076 // This is context
77 else if (this.number == CONTEXT) {
78 // DO nothing
79 }
80
Akron99220ea2018-01-30 19:09:20 +010081 // This is a relation target
Nils Diewalddcd5ab12015-02-20 02:59:09 +000082 else if (this.number < -1) {
Akron1c126b42018-01-30 19:48:48 +010083
84 // Create id
85 String id = escapeHTML(
86 match.getPosID(match.getClassID(this.number))
87 );
88
89 // ID already in use - create join
90 if (joins.contains(id)) {
Akrond5789302018-01-31 09:18:14 +010091 sb.append("<span xlink:show=\"other\" data-action=\"join\" xlink:href=\"#")
Akron1c126b42018-01-30 19:48:48 +010092 .append(id)
93 .append("\">");
94 }
95
96 // Not yet in use - create
97 else {
98 sb.append("<span xml:id=\"")
99 .append(id)
100 .append("\">");
101 joins.add(id);
102 };
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000103 }
Nils Diewaldbb33da22015-03-04 16:24:25 +0000104
Akron99220ea2018-01-30 19:09:20 +0100105 // This is an annotation
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000106 else if (this.number >= 256) {
107 sb.append("<span ");
108 if (this.number < 2048) {
109 sb.append("title=\"")
Eliza Margaretha6f989202016-10-14 21:48:29 +0200110 .append(escapeHTML(
111 match.getAnnotationID(this.number)))
112 .append('"');
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000113 }
Akron99220ea2018-01-30 19:09:20 +0100114
115 // This is a relation source
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000116 else {
117 Relation rel = match.getRelationID(this.number);
Akron47929692017-09-12 14:41:26 +0200118
119 if (DEBUG) {
120 log.trace("Annotation is a relation with id {}", this.number);
Akron652e4362017-09-18 20:14:44 +0200121 log.trace("Resulting in relation {}: {}-{}", rel.annotation, rel.refStart, rel.refEnd);
Akron47929692017-09-12 14:41:26 +0200122 };
123
Akron08f4ceb2016-08-03 23:53:32 +0200124 sb.append("xlink:title=\"")
Akron652e4362017-09-18 20:14:44 +0200125 .append(escapeHTML(rel.annotation))
Akrond5789302018-01-31 09:18:14 +0100126 .append("\" xlink:show=\"none\" xlink:href=\"#")
Akron652e4362017-09-18 20:14:44 +0200127 .append(escapeHTML(match.getPosID(rel.refStart, rel.refEnd)))
128 .append('"');
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000129 };
130 sb.append('>');
131 }
Nils Diewald52bd1cd2014-11-06 20:44:24 +0000132
Akron99220ea2018-01-30 19:09:20 +0100133 // This is a highlight
134 // < 256
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000135 else {
136 // Get the first free level slot
137 byte pos;
138 if (levelCache[this.number] != '\0') {
139 pos = levelCache[this.number];
140 }
141 else {
142 pos = (byte) level.nextSetBit(0);
143 level.clear(pos);
144 levelCache[this.number] = pos;
145 };
Nils Diewaldbb33da22015-03-04 16:24:25 +0000146 sb.append("<mark class=\"class-").append(this.number)
147 .append(" level-").append(pos).append("\">");
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000148 };
149 return sb.toString();
150 }
Akrond4b19332017-02-15 18:36:24 +0100151
Akron99220ea2018-01-30 19:09:20 +0100152 // This is a Closing tag
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000153 else if (this.type == 2) {
Akron12cd2582018-02-17 12:58:38 +0100154 if (this.number == CONTEXT)
155 return "";
156
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000157 if (this.number < -1 || this.number >= 256)
158 return "</span>";
Nils Diewaldbb33da22015-03-04 16:24:25 +0000159
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000160 if (this.number == -1)
161 return "</mark>";
Nils Diewaldbb33da22015-03-04 16:24:25 +0000162
Nils Diewalddcd5ab12015-02-20 02:59:09 +0000163 if (this.terminal)
164 level.set((int) levelCache[this.number]);
165 return "</mark>";
Akrond4b19332017-02-15 18:36:24 +0100166 }
167
168 // Empty element
169 else if (this.type == 3) {
170 return "<span class=\"pb\" data-after=\"" + number + "\"></span>";
171 };
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000172
Nils Diewaldbb33da22015-03-04 16:24:25 +0000173 // HTML encode primary data
174 return escapeHTML(this.characters);
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000175 };
176
Nils Diewaldbb33da22015-03-04 16:24:25 +0000177
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000178 // Return bracket fragment for this combinator element
Nils Diewald392bcf32015-02-26 20:01:17 +0000179 public String toBrackets (Match match) {
Nils Diewaldbb33da22015-03-04 16:24:25 +0000180 if (this.type == 1) {
181 StringBuilder sb = new StringBuilder();
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000182
Nils Diewaldbb33da22015-03-04 16:24:25 +0000183 // Match
184 if (this.number == -1) {
185 sb.append("[");
186 }
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000187
Akron12cd2582018-02-17 12:58:38 +0100188 // This is context
189 else if (this.number == CONTEXT) {
190 // DO nothing
191 }
192
Nils Diewaldbb33da22015-03-04 16:24:25 +0000193 // Identifier
194 else if (this.number < -1) {
195 sb.append("{#");
196 sb.append(match.getClassID(this.number));
197 sb.append(':');
198 }
199
200 // Highlight, Relation, Span
201 else {
202 sb.append("{");
203 if (this.number >= 256) {
204 if (this.number < 2048)
205 sb.append(match.getAnnotationID(this.number));
206 else {
207 Relation rel = match.getRelationID(this.number);
208 sb.append(rel.annotation);
Akron652e4362017-09-18 20:14:44 +0200209 sb.append('>').append(rel.refStart);
210
211 if (rel.refEnd != -1)
212 sb.append('-').append(rel.refEnd);
Nils Diewaldbb33da22015-03-04 16:24:25 +0000213 };
214 sb.append(':');
215 }
216 else if (this.number != 0)
217 sb.append(this.number).append(':');
218 };
Akronfc2625e2016-07-27 01:52:28 +0200219
Nils Diewaldbb33da22015-03-04 16:24:25 +0000220 return sb.toString();
221 }
222 else if (this.type == 2) {
Akron12cd2582018-02-17 12:58:38 +0100223
224 // This is context
225 if (this.number == CONTEXT)
226 return "";
227
Nils Diewaldbb33da22015-03-04 16:24:25 +0000228 if (this.number == -1)
229 return "]";
230 return "}";
231 };
Akronfc2625e2016-07-27 01:52:28 +0200232 return escapeBrackets(this.characters);
Nils Diewald79f6c4d2014-09-17 17:34:01 +0000233 };
234};