package esl.cuenet.source.accessors;
import com.hp.hpl.jena.enhanced.EnhGraph;
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.PrintUtil;
import com.hp.hpl.jena.vocabulary.RDF;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.util.Hash;
import com.mongodb.util.JSON;
import esl.cuenet.model.Constants;
import esl.cuenet.query.IResultIterator;
import esl.cuenet.query.IResultSet;
import esl.cuenet.query.ResultIterator;
import esl.cuenet.query.drivers.mongodb.MongoDB;
import esl.cuenet.source.AccesorInitializationException;
import esl.cuenet.source.Attribute;
import esl.cuenet.source.IAccessor;
import esl.cuenet.source.SourceQueryException;
import esl.datastructures.Location;
import esl.datastructures.TimeInterval;
import esl.system.JsonUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.ISO8601DateFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import java.util.*;
import java.util.regex.Pattern;
public class GoogleCalendarCollection extends MongoDB implements IAccessor {
private Logger logger = Logger.getLogger(GoogleCalendarCollection.class);
private Attribute[] attributes = null;
private boolean[] setFlags = new boolean[6];
private String ownerEmail = null;
private long startTime = -1;
private long endTime = -1;
private int errorMargin = 0;
private OntModel model = null;
private TimeInterval timeInterval = null;
//JODA
private DateTimeFormatter isoDateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
public GoogleCalendarCollection() {
super(AccessorConstants.DBNAME);
}
public GoogleCalendarCollection(OntModel model) {
this();
this.model = model;
}
public IResultSet query() {
DBReader cursor = startReader("google_calendar");
BasicDBObject query = new BasicDBObject();
if (setFlags[1]) {
query.put("email", ownerEmail);
}
if (setFlags[2]) {
query.put("start-time", new BasicDBObject("$lt", startTime+(errorMargin *60*1000)));
query.put("end-time", new BasicDBObject("$gt", endTime-(errorMargin *60*1000)));
query.put("start-time", startTime);
query.put("end-time", endTime);
}
if (timeInterval != null) {
startTime = timeInterval.getStart();
endTime = timeInterval.getEnd();
query.put("start-time", startTime);
query.put("end-time", endTime);
//query.put("start-time", new BasicDBObject("$lt", startTime+(errorMargin *60*1000)));
//query.put("end-time", new BasicDBObject("$gt", endTime-(errorMargin *60*1000)));
}
cursor.query(new BasicDBObject());
//cursor.query(query);
BasicDBList result = new BasicDBList();
int c=0;
while (cursor.hasNext()) {
DBObject object = cursor.next();
if ( !object.containsField("start-time") ) object = reformat((BasicDBObject) object);
if ( !object.containsField("start-time") ) continue;
if ( ((BasicDBObject)object).getLong("start-time") < query.getLong("start-time") &&
((BasicDBObject)object).getLong("end-time") > query.getLong("end-time")) {
logger.info("Gott itttttttttt! " + object.get("title"));
result.add(object);
c++;
}
}
logger.info("Found " + c + " calendar entries.");
return convertResults(result);
}
private DBObject reformat(BasicDBObject object) {
BasicDBObject formatted = new BasicDBObject();
if (object.containsField("summary")) formatted.put("title", object.getString("summary"));
if (object.containsField("type")) formatted.put("type", object.getString("type"));
if (object.containsField("link")) formatted.put("link", object.getString("link"));
if (JsonUtils.contains(object, "creator.displayName"))
formatted.put("name", JsonUtils.unnest(object, "creator.displayName", String.class));
if (JsonUtils.contains(object, "creator.email"))
formatted.put("email", JsonUtils.unnest(object, "creator.email", String.class));
if (JsonUtils.contains(object, "start.dateTime")) {
long t = isoDateTimeFormatter.parseMillis(JsonUtils.unnest(object, "start.dateTime", String.class));
formatted.put("start-time", t);
}
if (JsonUtils.contains(object, "end.dateTime")) {
long t = isoDateTimeFormatter.parseMillis(JsonUtils.unnest(object, "end.dateTime", String.class));
formatted.put("end-time", t);
}
return formatted;
}
private IResultSet convertResults(BasicDBList result) {
ResultSetImpl resultSet = new ResultSetImpl("Google Calendar Results", model);
OntClass event = null;
OntClass person = model.getOntClass(Constants.CuenetNamespace + "person");
DatatypeProperty nameProperty = model.getDatatypeProperty(
Constants.CuenetNamespace + "name");
DatatypeProperty emailProperty = model.getDatatypeProperty(
Constants.CuenetNamespace + "email");
DatatypeProperty titleProperty = model.getDatatypeProperty(
Constants.CuenetNamespace + "title");
ObjectProperty participatesInProperty = model.getObjectProperty(
Constants.DOLCE_Lite_Namespace + Constants.ParticipantIn);
ObjectProperty occursDuring = model.getObjectProperty(
Constants.CuenetNamespace + "occurs-during");
for (Object o: result) {
BasicDBObject entry = (BasicDBObject) o;
String title = null;
if (entry.containsField("type")) {
event = model.getOntClass(Constants.CuenetNamespace + entry.getString("type"));
if (event == null) throw new RuntimeException("Invalid type: " + entry.getString("type"));
title = entry.getString("title");
}
else if (entry.containsField("title")) {
title = entry.getString("title");
event = getOntologyClass(entry.getString("title"));
} else {
title = "geve";
event = model.getOntClass("http://www.w3.org/1999/02/22-rdf-syntax-ns#event");
}
Individual ev = event.createIndividual(Constants.CuenetNamespace + "event_" + title.replace(" ", "_"));
Individual owner = person.createIndividual();
if (entry.containsField("name")) owner.addLiteral(nameProperty, entry.getString("name"));
if (entry.containsField("email")) owner.addLiteral(emailProperty, entry.getString("email"));
if (entry.containsField("title")) ev.addLiteral(titleProperty, entry.getString("title"));
if (entry.containsField("start-time") && entry.containsField("end-time")) {
TimeInterval interval = TimeInterval.createFromInterval(entry.getLong("start-time"),
entry.getLong("end-time"), model);
ev.addProperty(occursDuring, interval);
}
if (entry.containsField("link")) {
Property urlProperty = model.getProperty(Constants.CuenetNamespace + "url");
ev.addProperty(urlProperty, entry.getString("link"));
}
List<Individual> resultEntry = new ArrayList<Individual>();
if (entry.containsField("participants")) {
BasicDBList parts = (BasicDBList) entry.get("participants");
for (Object op: parts) {
Individual participant = person.createIndividual(person.getURI() +
op.toString().replaceAll(" ", "_"));
participant.addLiteral(nameProperty, op);
participant.addProperty(participatesInProperty, ev);
resultEntry.add(participant);
}
}
owner.addProperty(participatesInProperty, ev);
resultEntry.add(ev);
resultEntry.add(owner);
resultSet.addResult(resultEntry);
}
return resultSet;
}
private OntClass getOntologyClass(String title) {
if (Pattern.compile(Pattern.quote("meet"), Pattern.CASE_INSENSITIVE).matcher(title).find())
return model.getOntClass("http://www.semanticweb.org/arjun/cuenet-main.owl#meeting");
else if (Pattern.compile(Pattern.quote("talk"), Pattern.CASE_INSENSITIVE).matcher(title).find())
return model.getOntClass("http://www.semanticweb.org/arjun/cuenet-main.owl#talk");
return model.getOntClass(Constants.DOLCE_Lite_Namespace + "event");
}
public BasicDBObject search(String username, long timestamp) {
String queryTemplate = String.format("{\"username\": \"%s\", \"start-time\": {\"$lt\": %d}, " +
"\"end-time\": {\"$gt\": %d}}", username,
timestamp+(errorMargin *60*1000), timestamp-(errorMargin * 60 * 1000));
DBReader cursor = startReader("google_calendar");
BasicDBObject query = (BasicDBObject)JSON.parse(queryTemplate);
cursor.query(query);
logger.info("Found " + cursor.count() + " records");
BasicDBObject tRecord = null;
while (cursor.hasNext()) tRecord = (BasicDBObject) cursor.next();
return tRecord;
}
@Override
public void setAttributeNames(Attribute[] attributes) throws AccesorInitializationException {
this.attributes = attributes;
}
@Override
public void start() {
for (int i=0; i<setFlags.length; i++) setFlags[i] = false;
/* re-init for next query */
startTime = -1;
endTime = -1;
}
@Override
public void associateTimeInterval(Attribute attribute, TimeInterval timeInterval) throws AccesorInitializationException {
this.timeInterval = timeInterval;
}
@Override
public void associateLocation(Attribute attribute, Location timeInterval) throws AccesorInitializationException {
throw new AccesorInitializationException("Incorrect Assignment: No location attributes in "
+ YahooPlaceFinderAPI.class.getName());
}
@Override
public void associateLong(Attribute attribute, long value) throws AccesorInitializationException {
if (attribute.compareTo(attributes[2])==0) { /* name */
setFlags[2] = true;
if (this.startTime != -1) endTime = value;
else startTime = value;
}
else
throw new AccesorInitializationException("Long value being initialized for wrong attribute "
+ FacebookUserAccessor.class.getName());
}
@Override
public void associateString(Attribute attribute, String value) throws AccesorInitializationException {
if (attribute.compareTo(attributes[1])==0) { /* name */
setFlags[1] = true;
this.ownerEmail = value;
}
else
throw new AccesorInitializationException("String value being initialized for wrong attribute "
+ FacebookUserAccessor.class.getName());
}
@Override
public void associateDouble(Attribute attribute, double value) throws AccesorInitializationException {
throw new AccesorInitializationException("Double value being initialized for wrong attribute "
+ FacebookUserAccessor.class.getName());
}
@Override
public IResultSet executeQuery() throws SourceQueryException {
return query();
}
}