package uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.DiseaseOccurrence;
import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.Location;
import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.Provenance;
import uk.ac.ox.zoo.seeg.abraid.mp.common.service.core.AlertService;
import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.DataAcquisitionException;
import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.DiseaseOccurrenceDataAcquirer;
import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap.domain.HealthMapAlert;
import uk.ac.ox.zoo.seeg.abraid.mp.dataacquisition.acquirers.healthmap.domain.HealthMapLocation;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Converts the retrieved HealthMap data into the ABRAID data structure.
*
* Copyright (c) 2014 University of Oxford
*/
public class HealthMapDataConverter {
private AlertService alertService;
private HealthMapLocationConverter locationConverter;
private HealthMapAlertConverter alertConverter;
private HealthMapLookupData lookupData;
private DiseaseOccurrenceDataAcquirer diseaseOccurrenceDataAcquirer;
private static final Logger LOGGER = Logger.getLogger(HealthMapDataAcquirer.class);
private static final String CONVERSION_MESSAGE =
"Converting %d HealthMap location(s), with %d alert(s) and %d GeoNames ID(s)";
private static final String COUNT_MESSAGE = "Saved %d HealthMap disease occurrence(s) in %d location(s)";
public HealthMapDataConverter(HealthMapLocationConverter locationConverter,
HealthMapAlertConverter alertConverter,
AlertService alertService,
HealthMapLookupData lookupData,
DiseaseOccurrenceDataAcquirer diseaseOccurrenceDataAcquirer) {
this.locationConverter = locationConverter;
this.alertConverter = alertConverter;
this.alertService = alertService;
this.lookupData = lookupData;
this.diseaseOccurrenceDataAcquirer = diseaseOccurrenceDataAcquirer;
}
/**
* Converts a list of HealthMap locations into ABRAID objects, and saves them to the database.
* Returns the occurrences for test purposes.
*
* @param healthMapLocations A list of HealthMap locations.
* @param endDate The end date for this HealthMap retrieval.
* @return The saved occurrences.
*/
public Set<DiseaseOccurrence> convert(List<HealthMapLocation> healthMapLocations, DateTime endDate) {
LOGGER.info(String.format(CONVERSION_MESSAGE, healthMapLocations.size(),
countHealthMapAlerts(healthMapLocations), countGeoNamesIdOccurrences(healthMapLocations)));
Set<DiseaseOccurrence> occurrences = convertHealthMapLocations(healthMapLocations);
writeLastRetrievalEndDate(endDate);
LOGGER.info(String.format(COUNT_MESSAGE, occurrences.size(), countUniqueLocations(occurrences)));
return occurrences;
}
private Set<DiseaseOccurrence> convertHealthMapLocations(List<HealthMapLocation> healthMapLocations) {
Set<DiseaseOccurrence> convertedOccurrences = new HashSet<>();
for (HealthMapLocation healthMapLocation : healthMapLocations) {
Location location = locationConverter.convert(healthMapLocation);
if (location != null) {
convertHealthMapAlert(healthMapLocation, location, convertedOccurrences);
}
}
return convertedOccurrences;
}
private void convertHealthMapAlert(HealthMapLocation healthMapLocation, Location location,
Set<DiseaseOccurrence> convertedOccurrences) {
if (healthMapLocation.getAlerts() != null) {
for (HealthMapAlert healthMapAlert : healthMapLocation.getAlerts()) {
for (DiseaseOccurrence occurrence : alertConverter.convert(healthMapAlert, location)) {
try {
if (diseaseOccurrenceDataAcquirer.acquire(occurrence)) {
convertedOccurrences.add(occurrence);
}
} catch (DataAcquisitionException e) {
// DataAcquisitionException should not cause a roll back (occurrence age check failed)
LOGGER.warn(e.getMessage());
}
}
}
}
}
private void writeLastRetrievalEndDate(DateTime retrievalDate) {
Provenance provenance = lookupData.getHealthMapProvenance();
provenance.setLastRetrievalEndDate(retrievalDate);
alertService.saveProvenance(provenance);
}
private int countHealthMapAlerts(List<HealthMapLocation> healthMapLocations) {
int count = 0;
for (HealthMapLocation healthMapLocation : healthMapLocations) {
if (healthMapLocation.getAlerts() != null) {
count += healthMapLocation.getAlerts().size();
}
}
return count;
}
private int countGeoNamesIdOccurrences(List<HealthMapLocation> healthMapLocations) {
int count = 0;
for (HealthMapLocation healthMapLocation : healthMapLocations) {
if (healthMapLocation.getGeoNameId() != null) {
count++;
}
}
return count;
}
private int countUniqueLocations(Set<DiseaseOccurrence> occurrences) {
Set<Integer> locationIDs = new HashSet<>();
for (DiseaseOccurrence occurrence : occurrences) {
if (occurrence.getLocation() != null) {
locationIDs.add(occurrence.getLocation().getId());
}
}
return locationIDs.size();
}
}