package esl.cuenet.algorithms.firstk.personal.accessor;
import com.google.common.collect.Lists;
import com.mongodb.BasicDBObject;
import esl.cuenet.algorithms.firstk.personal.EventContextNetwork;
import esl.cuenet.algorithms.firstk.personal.Location;
import esl.cuenet.algorithms.firstk.personal.Main;
import esl.cuenet.algorithms.firstk.personal.Time;
import esl.cuenet.query.drivers.mongodb.MongoDB;
import esl.cuenet.source.accessors.Utils;
import org.apache.log4j.Logger;
import javax.mail.internet.MailDateFormat;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class Email implements Source {
private Logger logger = Logger.getLogger(Email.class);
private SimpleDateFormat rfc2822DateFormatter = new MailDateFormat();
private final List<EmailObject> emails;
private Candidates candidateList = Candidates.getInstance();
protected Email() {
MailLoader loader = new MailLoader();
this.emails = loader.load();
logger.info("Loaded " + emails.size() + " emails.");
}
private static Email instance = new Email();
public static Email getInstance() {
return instance;
}
@Override
public List<EventContextNetwork> eventsContaining(Candidates.CandidateReference person, Time interval, Location location) {
return null;
}
@Override
public List<EventContextNetwork> participants(EventContextNetwork.Event event) {
return null;
}
@Override
public List<EventContextNetwork> subevents(EventContextNetwork.Event event) {
return null;
}
@Override
public List<Candidates.CandidateReference> knows(Candidates.CandidateReference person) {
return null;
}
int days = 1;
@Override
public List<EventContextNetwork> knowsAtTime(Candidates.CandidateReference person, Time time) {
if ( !time.isMoment() ) throw new RuntimeException("time should be a moment");
HashSet<Candidates.CandidateReference> candidates = new HashSet<Candidates.CandidateReference>();
long msGap = (long) days * 24 * 3600 * 1000;
Time start = time.subtract(msGap);
Time end = time.add(msGap);
//System.out.println(new Date(start.getStart()) + " " + new Date(end.getStart()));
List<EventContextNetwork> events = Lists.newArrayList();
for (EmailObject email: emails) {
if ( ! ( start.isBefore(email.time) && email.time.isBefore(end) ) ) continue;
if ( !email.references.contains(person) ) continue;
///System.out.println(email.nameMailPairs + " " + new Date(email.time.getStart()));
EventContextNetwork network = new EventContextNetwork();
EventContextNetwork.ECNRef mailRef = network.createEvent("email-exchange-event", email.time.getStart(), email.time.getEnd());
candidates.addAll(email.references);
for (Candidates.CandidateReference ref: candidates) {
network.createPartiticipationEdge(mailRef, network.createPerson(ref));
}
events.add(network);
}
days = 150;
return events;
}
@Override
public void writeInstances(FileWriter instanceFileWriter) throws IOException {
int instance_count = 0;
int email_event_id = 7;
Candidates.CandidateReference user = new Candidates.CandidateReference(0);
for (EmailObject obj: emails) {
instance_count++;
instanceFileWriter.write(email_event_id + " " + instance_count);
instanceFileWriter.write('\n');
obj.references.remove(user);
instanceFileWriter.write(email_event_id + ", " + obj.references.toString() + ", " + obj.time.getStart());
instanceFileWriter.write('\n');
instanceFileWriter.write("=========================================\n");
}
}
public class EmailObject {
List<Map.Entry<String, String>> nameMailPairs;
List<Candidates.CandidateReference> references;
Time time;
}
public class MailLoader extends MongoDB {
public MailLoader() {
super(PConstants.DBNAME);
}
public List<EmailObject> load() {
MongoDB.DBReader reader = startReader("emails");
reader.getAll(new BasicDBObject());
Time moment = null, start = null, end = null;
if (Main.EXIF != null) {
moment = Time.createFromMoment(Main.EXIF.timestamp);
end = moment.add((long) 25 * 24 * 3600 * 1000);
start = moment.subtract((long) 25 * 24 * 3600 * 1000);
}
logger.info("Loading mails from " + PConstants.DBNAME);
int ix = 0;
String to, from, cc, date;
List<EmailObject> emails = new ArrayList<EmailObject>();
while (reader.hasNext()) {
BasicDBObject obj = (BasicDBObject) reader.next();
EmailObject email = new EmailObject();
date = obj.getString("date");
if (date.length() < 1) continue;
email.time = getDate(date);
if (Main.EXIF != null) {
boolean f = start.isBefore(email.time) && email.time.isBefore(end);
if (!f) continue;
}
email.nameMailPairs = Lists.newArrayList();
to = obj.getString("to");
if (to != null) email.nameMailPairs.addAll(Utils.parseEmailAddresses(to));
from = obj.getString("from");
if (from != null) email.nameMailPairs.addAll(Utils.parseEmailAddresses(from));
cc = obj.getString("cc");
if (cc != null) email.nameMailPairs.addAll(Utils.parseEmailAddresses(cc));
checkCandidates(email);
emails.add(email);
ix++;
if (ix % 1000 == 0) logger.info("Loaded " + ix + " emails.");
}
close();
return emails;
}
private void checkCandidates(EmailObject emailObject) {
emailObject.references = Lists.newArrayList();
for (Map.Entry<String, String> pair: emailObject.nameMailPairs) {
String email = pair.getKey().toLowerCase();
String name = pair.getValue();
List<String> keys = Lists.newArrayList();
List<String> values = Lists.newArrayList();
keys.add(Candidates.EMAIL_KEY);
values.add(email);
if (name != null) {
name = name.toLowerCase();
keys.add(Candidates.NAME_KEY);
values.add(name);
}
Candidates.CandidateReference cReference = null;
cReference = candidateList.createEntity(keys, values);
/*
cReference = candidateList.search(Candidates.EMAIL_KEY, email);
if (cReference.equals(Candidates.UNKNOWN) && name != null) cReference = candidateList.search(Candidates.NAME_KEY, name);
if (cReference.equals(Candidates.UNKNOWN)) cReference = candidateList.createCandidate(Candidates.EMAIL_KEY, email);
candidateList.add(cReference, Candidates.EMAIL_KEY, email);
if (name != null) candidateList.add(cReference, Candidates.NAME_KEY, name);
*/
if ( !emailObject.references.contains(cReference) ) emailObject.references.add(cReference);
}
}
private Time getDate(String date) {
long ms = 0;
if (date != null) {
try {
ms = (rfc2822DateFormatter.parse(date)).getTime();
} catch (ParseException e) {
logger.error("RFC2822 Date Parsing failed: " + date + " " + e.getMessage());
}
} else {
logger.info("Date is null!");
}
return Time.createFromMoment(ms);
}
}
}