package edu.mit.simile.fresnel.results;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import org.openrdf.model.BNode;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.impl.StatementImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import edu.mit.simile.fresnel.FresnelUtilities;
import edu.mit.simile.fresnel.configuration.Group;
import edu.mit.simile.fresnel.selection.Lens;
/**
* Lens selection and formatting result for a resource.
*
* @author ryanlee
*/
public class Result implements ResultConstants {
/**
* Identifies the resource
*/
private Resource _origin;
/**
* Label for the resource
*/
private Title _title;
/**
* Content formatting
*/
private ContentSet _contents;
/**
* Styling classes
*/
private String _styles;
/**
* Lens used to select data
*/
private Lens _lens;
/**
* Group lens belongs to
*/
private Group _group;
/**
* Set of properties's results associated with this resource
*/
private PropertyResultSet _properties;
/**
* Set of rdf:type values associated with this resource
*/
private Set<Resource> _types;
/**
* Constructor based on resource with lens and group used to select it
*
* @param focus The <code>Resource</code> this result is for
* @param group The <code>Group</code> of Fresnel configurations used to select and format it
* @param lens The <code>Lens</code> used to select data
*/
public Result(Resource focus, Group group, Lens lens, Repository in) {
this._origin = focus;
this._properties = new PropertyResultSet();
this._contents = new ContentSet();
this._lens = lens;
this._group = group;
this._types = new HashSet<Resource>();
setTypes(in);
}
/**
* The identifying resource
*
* @return Identifying <code>Resource</code>
*/
public Resource getOrigin() {
return this._origin;
}
/**
* The lens used to select this resource and its data.
*
* @return Selecting <code>Lens</code>
*/
public Lens getLens() {
return this._lens;
}
/**
* The group the lens and subsequent formatting belongs to
*
* @return Parent <code>Group</code>
*/
public Group getGroup() {
return this._group;
}
/**
* A container for a human friendly label for the result
*
* @return A <code>Title</code>
*/
public Title getTitle() {
return this._title;
}
/**
* Retrieves the resource for this result as a URI.
*
* @return The resource's <code>URI</code>
*/
public String getURI() {
return this._origin.toString();
// TODO: may not be a URI...what then?
/* if ((this._origin instanceof BNode))
return ((URI) this._origin).toString();
else
return ((URI) this._origin).toString();*/
}
/**
* Retrieves formatting for the resource.
*
* @return A <code>ContentSet</code>
*/
public ContentSet getContents() {
return this._contents;
}
/**
* Retrieves styling classes for the resource.
*
* @return A <code>String</code>
*/
public String getStyles() {
return this._styles;
}
/**
* Retrieves the properties' results associated with the resource
*
* @return A <code>PropertyResultSet</code>
*/
public PropertyResultSet getProperties() {
return this._properties;
}
/**
* Fetches rdf:type values for the resource
*
* @return A <code>RdfTypeSet</code>
*/
public Set<Resource> getTypes() {
return this._types;
}
/**
* Return type statements as a statement iterator.
*
* @return A <code>StatementIterator</code>.
*/
public Iterator<Statement> getTypesStatements() {
Vector<Statement> out = new Vector<Statement>();
for (Resource r : getTypes()) {
out.add(new StatementImpl(getOrigin(), RDF.TYPE, r));
}
return out.iterator();
}
/**
* Sets rdf:type values for the resource
*
* @param in Data <code>Repository</code>
*/
public void setTypes(Repository in) {
try {
RepositoryConnection conn = in.getConnection();
RepositoryResult<Statement> si = conn.getStatements(getOrigin(), RDF.TYPE, null, true);
while (si.hasNext()) {
Statement s = si.next();
this._types.add((Resource) FresnelUtilities.dupValue(s.getObject()));
}
si.close();
conn.close();
} catch (RepositoryException e) {
// TODO: how to handle this exception
}
}
/**
* Sets the human friendly title.
*
* @param title A <code>Title</code>
*/
public void setTitle(Title title) {
this._title = title;
}
/**
* Sets the style class.
*
* @param style A <code>String</code>
*/
public void setStyles(String style) {
this._styles = style;
}
/**
* Sets the formatting for the result.
*
* @param contents A <code>ContentSet</code>
*/
public void setContents(ContentSet contents) {
this._contents = contents;
}
/**
* Adds a property result to the existing set of property results
*
* @param prop A <code>PropertyResult</code>
*/
public void addProperty(PropertyResult prop) {
this._properties.addPropertyResult(prop, this);
}
/**
* Renders the result and everything attached to it to an element in
* the Fresnel XML tree output.
*
* @param doc A <code>Document</code> for creating elements.
* @return An <code>Element</code> for the result, e.g.:
* <resource><title>I'm a result</title> ... </resource>
*/
public Element render(Document doc) {
Element out = doc.createElementNS(INTERMEDIATE_NS, "resource");
out.setAttribute("class", getStyles());
out.setAttribute("uri", getURI());
if (getGroup().hasCssLinks()) {
for (Iterator linkIt = getGroup().getCssLinks().iterator(); linkIt.hasNext(); ) {
Element link = doc.createElementNS(INTERMEDIATE_NS, "link");
link.appendChild(doc.createTextNode((String) linkIt.next()));
out.appendChild(link);
}
}
Element title = doc.createElementNS(INTERMEDIATE_NS, "title");
if (null != getTitle())
title.appendChild(doc.createTextNode(getTitle().getString()));
else
title.appendChild(doc.createTextNode("(untitled)"));
out.appendChild(title);
Element content = getContents().render(doc);
if (content.hasChildNodes()) out.appendChild(content);
for(Iterator<PropertyResult> it = getProperties().propertyResultIterator(); it.hasNext() ; ) {
PropertyResult pr = it.next();
Element prop = null;
if (pr.isInModel())
prop = pr.render(doc);
else
prop = ((NoSuchPropertyResult) pr).render(doc);
if (null != prop)
out.appendChild(prop);
}
return out;
}
}