/*******************************************************************************
* Copyright 2013
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.tudarmstadt.ukp.csniper.webapp.analysis;
import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.KEY_RENDERING;
import static java.awt.RenderingHints.KEY_STROKE_CONTROL;
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
import static java.awt.RenderingHints.VALUE_RENDER_QUALITY;
import static java.awt.RenderingHints.VALUE_STROKE_PURE;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
import static org.apache.uima.fit.util.CasUtil.getType;
import static org.apache.uima.fit.util.CasUtil.select;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.imageio.ImageIO;
import org.apache.uima.cas.CASException;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.cas.FSArray;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.wicket.request.resource.DynamicImageResource;
import org.apache.wicket.util.time.Time;
import annis.frontend.servlets.visualizers.Visualizer;
import annis.frontend.servlets.visualizers.tree.TigerTreeVisualizer;
import annis.model.AnnisNode;
import annis.model.AnnotationGraph;
import annis.model.Edge;
import annis.model.Edge.EdgeType;
import de.tudarmstadt.ukp.csniper.treevisualizer.AnnisResultIncompleteImpl;
import de.tudarmstadt.ukp.csniper.webapp.search.tgrep.PennTreeNode;
import de.tudarmstadt.ukp.csniper.webapp.search.tgrep.PennTreeUtils;
import de.tudarmstadt.ukp.csniper.webapp.support.uima.CasHolder;
import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence;
import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.constituent.Constituent;
import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.constituent.ROOT;
public class ParseTreeResource
extends DynamicImageResource
{
private static final long serialVersionUID = -7078485350723019878L;
private static final String NAMESPACE = "testrat";
transient private Map<Annotation, AnnisNode> nodes;
private final CasHolder casHolder;
private final String pennTree;
private int currentParse = 1;
public ParseTreeResource(CasHolder aCas)
{
casHolder = aCas;
pennTree = null;
}
public ParseTreeResource(String aPennTree)
{
casHolder = null;
pennTree = aPennTree;
}
public void setCurrentParse(int aCurrentParse)
{
if ((aCurrentParse <= getMaxParse()) && (aCurrentParse > 0)) {
currentParse = aCurrentParse;
}
}
public int getCurrentParse()
{
if (getMaxParse() == 0) {
return 0;
}
else {
return currentParse;
}
}
public int getMaxParse()
{
if (casHolder != null && casHolder.getCas() != null) {
return select(casHolder.getCas(), getType(casHolder.getCas(), Sentence.class)).size();
}
else if (pennTree != null) {
return 1;
}
else {
return 0;
}
}
@Override
protected byte[] getImageData(Attributes aArg0)
{
setLastModifiedTime(Time.now());
if ((casHolder == null || casHolder.getCas() == null) && pennTree == null) {
BufferedImage image = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB);
Graphics2D canvas = (Graphics2D) image.getGraphics();
canvas.setRenderingHint(KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON);
canvas.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
canvas.setRenderingHint(KEY_RENDERING, VALUE_RENDER_QUALITY);
canvas.setRenderingHint(KEY_STROKE_CONTROL, VALUE_STROKE_PURE);
canvas.drawString("No data", 0, 0);
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "png", bos);
return bos.toByteArray();
}
catch (IOException e) {
return new byte[0];
}
}
else {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Visualizer ttv = new TigerTreeVisualizer();
if (pennTree != null) {
ttv.setResult(new AnnisResultIncompleteImpl(createGraphFromPennTree(pennTree)));
}
else {
ttv.setResult(new AnnisResultIncompleteImpl(createGraph(casHolder.getCas()
.getJCas())));
}
ttv.setMappings(new Properties());
ttv.setNamespace(NAMESPACE);
ttv.writeOutput(bos);
return bos.toByteArray();
}
catch (CASException e) {
throw new RuntimeException(e);
}
}
}
private AnnotationGraph createGraph(JCas aJCas)
{
// Fetch parse tree
ROOT root = JCasUtil.selectByIndex(aJCas, ROOT.class, currentParse - 1);
// Build model
nodes = new HashMap<Annotation, AnnisNode>();
AnnisNode rootV = getAnnisNode(aJCas, null, root);
nodes.put(root, rootV);
traverse(aJCas, root);
// Populate graph
AnnotationGraph graph = new AnnotationGraph();
for (AnnisNode node : nodes.values()) {
graph.addNode(node);
}
return graph;
}
private void traverse(JCas aJCas, Constituent parent)
{
FSArray children = parent.getChildren();
AnnisNode parentNode = getAnnisNode(aJCas, null, parent);
annis.model.Annotation nodeAnno = new annis.model.Annotation(NAMESPACE, "cat",
parent.getConstituentType());
parentNode.addNodeAnnotation(nodeAnno);
nodes.put(parent, parentNode);
for (int i = 0; i < children.size(); i++) {
Annotation child = parent.getChildren(i);
// create/save node
AnnisNode childNode = getAnnisNode(aJCas, parentNode, child);
nodes.put(child, childNode);
// traverse deeper
if (child instanceof Constituent) {
traverse(aJCas, (Constituent) child);
}
}
}
private AnnisNode getAnnisNode(JCas aJCas, AnnisNode aParentNode, Annotation aChild)
{
AnnisNode parentNode = aParentNode;
AnnisNode node = nodes.get(aChild);
if (node == null) {
long id = aChild.hashCode();
node = new AnnisNode(id);
node.setRoot(aChild.getClass() == ROOT.class);
node.setNamespace(NAMESPACE);
node.setSpannedText(aChild.getCoveredText());
if (aChild instanceof Constituent) {
Constituent constituent = (Constituent) aChild;
node.setToken(false);
// create/save edge
if (parentNode != null) {
Edge edge = createEdge(parentNode, node);
String synFunc = constituent.getSyntacticFunction();
edge.addAnnotation(new annis.model.Annotation(NAMESPACE, "func", synFunc));
}
}
else if (aChild instanceof Token) {
Token token = (Token) aChild;
if (token.getPos() != null && token.getPos().getPosValue() != null) {
AnnisNode posNode = new AnnisNode(token.getPos().hashCode());
posNode.setRoot(false);
posNode.setToken(false);
posNode.setNamespace(NAMESPACE);
posNode.setSpannedText(aChild.getCoveredText());
posNode.addNodeAnnotation(new annis.model.Annotation(NAMESPACE, "cat", token
.getPos().getPosValue()));
if (parentNode != null) {
createEdge(parentNode, posNode);
}
parentNode = posNode;
}
node.setToken(true);
Long idx = (long) JCasUtil.selectCovered(aJCas, Token.class, 0, aChild.getBegin())
.size();
node.setTokenIndex(idx);
if (parentNode != null) {
createEdge(parentNode, node);
}
}
}
return node;
}
private Edge createEdge(AnnisNode parentNode, AnnisNode childNode)
{
// create edge
Edge edge = new Edge();
edge.setName("edge");
edge.setSource(parentNode);
edge.setDestination(childNode);
edge.setEdgeType(EdgeType.DOMINANCE);
// add edges to nodes
parentNode.addOutgoingEdge(edge);
childNode.addIncomingEdge(edge);
return edge;
}
// ----
private AnnotationGraph createGraphFromPennTree(String aTree)
{
// Fetch parse tree
PennTreeNode root = PennTreeUtils.parsePennTree(aTree);
// Build model
List<AnnisNode> nodes = traverse(null, root);
// Populate graph
AnnotationGraph graph = new AnnotationGraph();
for (AnnisNode node : nodes) {
graph.addNode(node);
}
return graph;
}
private List<AnnisNode> traverse(AnnisNode aParent, PennTreeNode aChild)
{
List<AnnisNode> nodes = new ArrayList<AnnisNode>();
AnnisNode node = new AnnisNode(aChild.hashCode());
annis.model.Annotation nodeAnno = new annis.model.Annotation(NAMESPACE, "cat",
aChild.getLabel());
node.addNodeAnnotation(nodeAnno);
node.setNamespace(NAMESPACE);
node.setSpannedText(aChild.getCoveredText());
if (aParent == null) {
node.setRoot(true);
}
else {
node.setRoot(false);
createEdge(aParent, node);
}
if (aChild.isTerminal()) {
node.setToken(true);
node.setTokenIndex((long) aChild.getNodeStartIndex());
}
else {
node.setToken(false);
}
nodes.add(node);
for (PennTreeNode grandChild : aChild.getChildren()) {
nodes.addAll(traverse(node, grandChild));
}
return nodes;
}
}