package org.activityinfo.core.shared.importing.strategy; import com.google.common.base.Function; import com.google.common.collect.Lists; import org.activityinfo.core.client.InstanceQuery; import org.activityinfo.core.client.ResourceLocator; import org.activityinfo.model.resource.ResourceId; import org.activityinfo.core.shared.Projection; import org.activityinfo.core.shared.criteria.ClassCriteria; import org.activityinfo.model.form.FormInstance; import org.activityinfo.model.formTree.FieldPath; import org.activityinfo.core.shared.importing.source.SourceRow; import org.activityinfo.core.shared.importing.validation.ValidationResult; import org.activityinfo.model.type.FieldValue; import org.activityinfo.model.type.primitive.TextValue; import org.activityinfo.promise.Promise; import javax.annotation.Nullable; import java.util.List; import java.util.Map; public class SingleClassImporter implements FieldImporter { private ResourceId rangeClassId; private ResourceId fieldId; private boolean required; /** * List of columns to match against name properties of potential reference matches. */ private List<ColumnAccessor> sources; private List<FieldImporterColumn> fieldImporterColumns = Lists.newArrayList(); /** * The list of nested text fields to match against, mapped to the * index of the column they are to be matched against. */ private Map<FieldPath, Integer> referenceFields; private InstanceScoreSource scoreSource; private InstanceScorer instanceScorer = null; public SingleClassImporter(ResourceId rangeClassId, boolean required, List<ColumnAccessor> sourceColumns, Map<FieldPath, Integer> referenceFields, List<FieldImporterColumn> fieldImporterColumns, ResourceId fieldId) { this.rangeClassId = rangeClassId; this.required = required; this.sources = sourceColumns; this.referenceFields = referenceFields; this.fieldImporterColumns = fieldImporterColumns; this.fieldId = fieldId; } public Promise<Void> prepare(ResourceLocator locator, List<? extends SourceRow> batch) { InstanceQuery query = new InstanceQuery( Lists.newArrayList(referenceFields.keySet()), new ClassCriteria(rangeClassId)); return locator.query(query).then(new Function<List<Projection>, Void>() { @Nullable @Override public Void apply(List<Projection> projections) { scoreSource = new InstanceScoreSourceBuilder(referenceFields, sources).build(projections); instanceScorer = new InstanceScorer(scoreSource); return null; } }); } public static String[] toArray(Projection projection, Map<FieldPath, Integer> referenceFields, int arraySize) { String[] values = new String[arraySize]; for (Map.Entry<FieldPath, FieldValue> entry : projection.getValueMap().entrySet()) { Integer index = referenceFields.get(entry.getKey()); if (index != null) { Object value = entry.getValue(); if (value instanceof TextValue) { values[index] = ((TextValue) value).asString(); } } } return values; } @Override public void validateInstance(SourceRow row, List<ValidationResult> results) { final InstanceScorer.Score score = instanceScorer.score(row); final int bestMatchIndex = score.getBestMatchIndex(); for (int i = 0; i != sources.size(); ++i) { if (score.getImported()[i] == null) { if(required) { results.add(ValidationResult.error("required missing")); } else { results.add(ValidationResult.MISSING); } } else if (bestMatchIndex == -1) { results.add(ValidationResult.error("No match")); } else { String matched = scoreSource.getReferenceValues().get(bestMatchIndex)[i]; final ValidationResult converted = ValidationResult.converted(matched, score.getBestScores()[i]); converted.setInstanceId(scoreSource.getReferenceInstanceIds().get(bestMatchIndex)); results.add(converted); } } } @Override public boolean updateInstance(SourceRow row, FormInstance instance) { // root final List<ValidationResult> validationResults = Lists.newArrayList(); validateInstance(row, validationResults); for (ValidationResult result : validationResults) { if (result.shouldPersist() && result.getInstanceId() != null) { instance.set(fieldId, result.getInstanceId()); } } // nested data // todo ??? return true; } @Override public List<FieldImporterColumn> getColumns() { return fieldImporterColumns; } }