package uk.ac.ebi.quickgo.annotation.validation;

import uk.ac.ebi.quickgo.annotation.validation.model.DBXRefEntity;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.batch.item.ItemWriter;

/**
 * Use the database cross reference information contain in this class to verify a list of potential database cross
 * reference identifiers.
 *
 * @author Tony Wardell
 * Date: 08/11/2016
 * Time: 14:41
 * Created with IntelliJ IDEA.
 */
public class DBXRefEntityValidation implements ConstraintValidator<WithFromValidator, String[]> {

    private final static Map<String, List<DBXRefEntity>> mappedEntities = new HashMap<>();

    private static Function<String,String>  toDb = (value) -> value.substring(0, value.indexOf(":")).toLowerCase();
    private static Function<String, String> toId = (value) -> value.substring(value.indexOf(":") + 1);

    @Override public void initialize(WithFromValidator constraintAnnotation) {

    }

    /**
     * If the entire list of values passed to isValid can be successfully validated, or not validated at all then
     * isValid will return true.
     * @param values list of potential database cross reference identifiers. Can be null.
     * @param context of the isValid call.
     * @return validation result as boolean.
     */
    @Override public boolean isValid(String[] values, ConstraintValidatorContext context) {
        return values == null || Stream.of(values)
                .allMatch(this::valueIsValid);
    }

    private boolean valueIsValid(String value) {
        return !value.contains(":") || (isValidForDb(value));
    }

    private boolean isValidForDb(String value) {
        final List<DBXRefEntity> entities = mappedEntities.get(toDb.apply(value));
        return entities != null && entities.stream().anyMatch(e -> e.test(toId.apply(value)));
    }

    static class DBXRefEntityAggregator implements ItemWriter<DBXRefEntity> {

        @Override public void write(List<? extends DBXRefEntity> items) {
            Preconditions.checkArgument(items != null, "The list of DBXRefEntity written to DBXRefEntityAggregator " +
                    "cannot be null.");

            for (DBXRefEntity item : items) {
                mappedEntities.computeIfAbsent(item.database.toLowerCase(), k -> new ArrayList<>()).add(item);
            }
        }
    }
}

@@ -145,89 +145,21 @@
 ase.
-Function;%0Aimport com.google.common.base.Preconditions;%0Aimport java.util.ArrayList
+Preconditions
 ;%0Aim
@@ -223,24 +223,86 @@
 a.util.Map;%0A
+import java.util.Objects;%0Aimport java.util.function.Function;%0A
 import java.
@@ -469,16 +469,71 @@
 riter;%0A%0A
+import static java.util.stream.Collectors.groupingBy;%0A%0A
 /**%0A * U
@@ -877,22 +877,16 @@
 private 
-final 
 static M
@@ -986,24 +986,24 @@
 %3CString,
+ 
 String%3E
- 
  toDb = 
@@ -2477,166 +2477,211 @@
     
-for (DBXRefEntity item : items) %7B%0A                mappedEntities.computeIfAbsent(item.database.toLowerCase(), k -%3E new ArrayList%3C%3E()).add(item);%0A            %7D
+mappedEntities = items.stream()%0A                    .filter(Objects::nonNull)%0A                    .filter(i -%3E i.database != null)%0A                    .collect(groupingBy(i -%3E i.database.toLowerCase()));
 %0A   

Deal with nulls in DBXRefEntity list. Move to code to java 8 stream in write method.