/*
* Copyright (C) 2011 Andrea Schweer
*
* This file is part of the Digital Parrot.
*
* The Digital Parrot is free software; you can redistribute it and/or modify
* it under the terms of the Eclipse Public License as published by the Eclipse
* Foundation or its Agreement Steward, either version 1.0 of the License, or
* (at your option) any later version.
*
* The Digital Parrot is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License for
* more details.
*
* You should have received a copy of the Eclipse Public License along with the
* Digital Parrot. If not, see http://www.eclipse.org/legal/epl-v10.html.
*
*/
package net.schweerelos.parrot.model;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Comparator;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.ISODateTimeFormat;
import org.mindswap.pellet.jena.ModelExtractor;
import org.mindswap.pellet.jena.ModelExtractor.StatementType;
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.datatypes.xsd.XSDDateTime;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
public class NodeWrapper implements Comparable<NodeWrapper> {
public static final class ToStringComparator implements
Comparator<NodeWrapper> {
@Override
public int compare(NodeWrapper o1, NodeWrapper o2) {
return o1.toString().compareTo(o2.toString());
}
}
private static final DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT);
private OntResource ontResource;
private Literal literal;
private boolean highlighted;
private boolean hereTooSelected;
private String label;
private String toolTip;
private boolean hasCreatedToolTip = false;
public NodeWrapper(OntResource node) {
this.ontResource = node;
}
public NodeWrapper(Literal literal) {
this.literal = literal;
}
public String toString() {
if (label == null) {
if (isOntResource()) {
label = extractLabel(ontResource);
} else if (isLiteral()) {
label = extractLabel(literal);
} else {
label = ""; // TODO does this cause problems?
}
}
return label;
}
@Override
public int compareTo(NodeWrapper o) {
//System.out.println("NodeWrapper: comparing " + this + " (" + this.hashCode() + ") to " + o + " (" + o.hashCode() + ")");
int comparison = toString().compareTo(o.toString());
if (comparison != 0) {
return comparison;
}
// equal strings
if (isLiteral() && o.isLiteral()) {
return literal.toString().compareTo(o.literal.toString());
} else if (isOntResource() && o.isOntResource()) {
if (ontResource.isProperty() && o.ontResource.isProperty()) {
return new Integer(ontResource.hashCode()).compareTo(o.ontResource.hashCode());
} else {
String thisURI = ontResource.getURI();
String otherURI = o.ontResource.getURI();
if (thisURI != null && otherURI != null) {
return thisURI.compareTo(otherURI);
} else if (thisURI != null) {
return -1;
} else if (otherURI != null) {
return 1;
} else {
// both null
return 0;
}
}
} else {
// highly unlikely that we ever get here: a literal looks like a resource
return comparison;
}
}
//
// @Override
// public boolean equals(Object obj) {
// if (!(obj instanceof NodeWrapper)) {
// return false;
// }
// NodeWrapper other = (NodeWrapper) obj;
// return compareTo(other) == 0;
// }
public boolean isLiteral() {
return literal != null;
}
public boolean isOntResource() {
return !isLiteral();
}
public OntResource getOntResource() {
return ontResource;
}
public Literal getLiteral() {
return literal;
}
public void setHighlighted(boolean highlighted) {
this.highlighted = highlighted;
}
public boolean isHighlighted() {
return highlighted;
}
public void setHereTooSelected(boolean hereTooSelected) {
this.hereTooSelected = hereTooSelected;
}
public boolean isHereTooSelected() {
return hereTooSelected;
}
private static String extractLabel(Literal literal) {
String label;
if (literal.getDatatype() == null) {
label = literal.getLexicalForm();
} else {
Object literalValue = literal.getValue();
if (literalValue instanceof XSDDateTime) {
Calendar date = ((XSDDateTime) literalValue).asCalendar();
label = DATE_FORMAT.format(date.getTime());
} else {
label = literalValue.toString();
}
}
return label;
}
private static String extractLabel(OntResource resource) {
String result;
String enLabel = resource.getLabel("en");
if (enLabel != null && !enLabel.equals("")) {
result = enLabel;
} else {
String label = resource.getLabel(null);
if (label != null && !label.equals("")) {
result = label;
} else {
result = resource.getLocalName();
}
}
return result;
}
public String getToolTipText(ParrotModel model) {
if (!hasCreatedToolTip) {
toolTip = createToolTip(model);
hasCreatedToolTip = true;
}
return toolTip;
}
private String createToolTip(ParrotModel model) {
if (!isOntResource()) {
return "";
}
OntResource resource = getOntResource();
if (!resource.isIndividual() || resource.isProperty()) {
return "";
}
StringBuilder text = new StringBuilder();
// use extracted model to speed up reasoning
OntModel ontModel = model.getOntModel();
ModelExtractor extractor = new ModelExtractor(ontModel);
extractor.setSelector(StatementType.PROPERTY_VALUE);
Model eModel = extractor.extractModel();
Resource eResource = eModel.getResource(resource.getURI());
StmtIterator props = eResource.listProperties();
while (props.hasNext()) {
Statement statement = props.nextStatement();
Property pred = statement.getPredicate();
if (!pred.isURIResource()) {
continue;
}
OntProperty ontPred = ontModel.getOntProperty(pred.getURI());
if (ontPred == null) {
continue;
}
if (ParrotModelHelper.showTypeAsSecondary(ontModel, ontPred)) {
// anything in the tooltip yet? if so, add line break
text.append(text.length() > 0 ? "<br>" : "");
// put in extracted predicate label
text.append(extractLabel(ontPred));
text.append(" ");
RDFNode object = statement.getObject();
if (object.isLiteral()) {
Literal literal = (Literal) object.as(Literal.class);
String lexicalForm = literal.getLexicalForm();
if (literal.getDatatype().equals(XSDDatatype.XSDdateTime)) {
DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
DateTime dateTime = parser.parseDateTime(lexicalForm);
DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder()
.appendMonthOfYearShortText()
.appendLiteral(' ')
.appendDayOfMonth(1)
.appendLiteral(", ")
.appendYear(4, 4)
.appendLiteral(", ")
.appendHourOfHalfday(1)
.appendLiteral(':')
.appendMinuteOfHour(2)
.appendHalfdayOfDayText()
.appendLiteral(" (")
.appendTimeZoneName()
.appendLiteral(", UTC")
.appendTimeZoneOffset("", true, 1, 1)
.appendLiteral(')');
String prettyDateTime = formatter.toFormatter().print(dateTime);
text.append(prettyDateTime);
} else {
text.append(lexicalForm);
}
} else if (object.isURIResource()) {
OntResource ontObject = ontModel.getOntResource((Resource) object.as(Resource.class));
if (ontObject == null) {
continue;
}
text.append(extractLabel(ontObject));
}
}
}
// surround with html tags
text.insert(0, "<html>");
text.append("</html>");
String result = text.toString();
if (result.equals("<html></html>")) {
result = "";
}
return result;
}
public boolean isType() {
if (!isOntResource()) {
return false;
}
return getOntResource().isClass();
}
}