package org.activityinfo.core.shared.importing.strategy; import org.activityinfo.core.client.ResourceLocator; import org.activityinfo.model.resource.ResourceId; import org.activityinfo.model.form.FormInstance; import org.activityinfo.core.shared.importing.source.SourceRow; import org.activityinfo.core.shared.importing.validation.ValidationResult; import org.activityinfo.model.type.geo.AiLatLng; import org.activityinfo.core.shared.type.converter.CoordinateAxis; import org.activityinfo.core.shared.type.converter.CoordinateFormatException; import org.activityinfo.core.shared.type.converter.CoordinateParser; import org.activityinfo.model.type.geo.GeoPoint; import org.activityinfo.promise.Promise; import java.util.Arrays; import java.util.List; /** * Importer for Lat/Lng */ public class GeographicPointImporter implements FieldImporter { private final ResourceId fieldId; private final ColumnAccessor[] sourceColumns; private final CoordinateParser[] coordinateParsers; private final List<FieldImporterColumn> fieldImporterColumns; public GeographicPointImporter(ResourceId fieldId, ColumnAccessor[] sourceColumns, ImportTarget[] targetSites, CoordinateParser.NumberFormatter coordinateNumberFormatter) { this.fieldId = fieldId; this.sourceColumns = sourceColumns; CoordinateParser latitudeParser = new CoordinateParser(CoordinateAxis.LATITUDE, coordinateNumberFormatter); CoordinateParser longitudeParser = new CoordinateParser(CoordinateAxis.LONGITUDE, coordinateNumberFormatter); latitudeParser.setRequireSign(false); longitudeParser.setRequireSign(false); this.coordinateParsers = new CoordinateParser[]{latitudeParser, longitudeParser }; this.fieldImporterColumns = Arrays.asList( new FieldImporterColumn(targetSites[0], sourceColumns[0]), new FieldImporterColumn(targetSites[1], sourceColumns[1])); } @Override public Promise<Void> prepare(ResourceLocator locator, List<? extends SourceRow> batch) { return Promise.done(); } @Override public List<FieldImporterColumn> getColumns() { return fieldImporterColumns; } @Override public void validateInstance(SourceRow row, List<ValidationResult> results) { boolean latitudeMissing = sourceColumns[0].isMissing(row); boolean longitudeMissing = sourceColumns[1].isMissing(row); if (latitudeMissing && longitudeMissing) { results.add(ValidationResult.MISSING); results.add(ValidationResult.MISSING); } else { results.add(validateCoordinate(row, 0)); results.add(validateCoordinate(row, 1)); } } private ValidationResult validateCoordinate(SourceRow row, int i) { if (sourceColumns[i].isMissing(row)) { return ValidationResult.error("Both latitude and longitude are required"); } try { double coordinate = parseCoordinate(row, i); // we reformat the coordinate make clear the conversion return ValidationResult.converted(coordinateParsers[i].format(coordinate), 1); } catch (Exception e) { return ValidationResult.error(e.getMessage()); } } private double parseCoordinate(SourceRow row, int i) throws CoordinateFormatException { String string = sourceColumns[i].getValue(row); return coordinateParsers[i].parse(string); } @Override public boolean updateInstance(SourceRow row, FormInstance instance) { final boolean isLatOk = validateCoordinate(row, 0).shouldPersist(); final boolean isLonOk = validateCoordinate(row, 1).shouldPersist(); if (isLatOk && isLonOk) { double latitude = parseCoordinate(row, 0); double longitude = parseCoordinate(row, 1); instance.set(fieldId, new GeoPoint(latitude, longitude)); return true; } return false; } }