blob: c39825a24d1704f2cff6e41849b63eeb44fcef02 [file] [log] [blame]
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.KrillString.*;
import java.util.*;
import java.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
Class for elements with highlighting information
*/
public class HighlightCombinatorElement {
// Number -1: Match
// Number -99998: Context
private final static int CONTEXT = -99998;
// Type 0: Textual data
// Type 1: Opening
// Type 2: Closing
// Type 3: Empty
public byte type;
public int number = 0;
public String characters;
public boolean terminal = true;
// Logger
private final static Logger log = LoggerFactory.getLogger(Match.class);
// This advices the java compiler to ignore all loggings
public static final boolean DEBUG = false;
// 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, HashSet joins) {
// Opening
if (this.type == 1) {
StringBuilder sb = new StringBuilder();
// This is the surrounding match mark
if (this.number == -1) {
sb.append("<mark>");
}
// This is context
else if (this.number == CONTEXT) {
// DO nothing
}
// This is a relation target
else if (this.number < -1) {
// Create id
String id = escapeHTML(
match.getPosID(match.getClassID(this.number))
);
// ID already in use - create join
if (joins.contains(id)) {
sb.append("<span xlink:show=\"other\" data-action=\"join\" xlink:href=\"#")
.append(id)
.append("\">");
}
// Not yet in use - create
else {
sb.append("<span xml:id=\"")
.append(id)
.append("\">");
joins.add(id);
};
}
// This is an annotation
else if (this.number >= 256) {
sb.append("<span ");
if (this.number < 2048) {
sb.append("title=\"")
.append(escapeHTML(
match.getAnnotationID(this.number)))
.append('"');
}
// This is a relation source
else {
Relation rel = match.getRelationID(this.number);
if (DEBUG) {
log.trace("Annotation is a relation with id {}", this.number);
log.trace("Resulting in relation {}: {}-{}", rel.annotation, rel.refStart, rel.refEnd);
};
sb.append("xlink:title=\"")
.append(escapeHTML(rel.annotation))
.append("\" xlink:show=\"none\" xlink:href=\"#")
.append(escapeHTML(match.getPosID(rel.refStart, rel.refEnd)))
.append('"');
};
sb.append('>');
}
// This is a 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();
}
// This is a Closing tag
else if (this.type == 2) {
if (this.number == CONTEXT)
return "";
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>";
}
// Empty element
else if (this.type == 3) {
return "<span class=\"pb\" data-after=\"" + number + "\"></span>";
};
// 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("[");
}
// This is context
else if (this.number == CONTEXT) {
// DO nothing
}
// 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.refStart);
if (rel.refEnd != -1)
sb.append('-').append(rel.refEnd);
};
sb.append(':');
}
else if (this.number != 0)
sb.append(this.number).append(':');
};
return sb.toString();
}
else if (this.type == 2) {
// This is context
if (this.number == CONTEXT)
return "";
if (this.number == -1)
return "]";
return "}";
};
return escapeBrackets(this.characters);
};
};