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

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

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<>();

    @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.
     * @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 String dbKey = value.substring(0, value.indexOf(":")).toLowerCase();
        final String id = value.substring(value.indexOf(":")+1);
        List<DBXRefEntity> entities = mappedEntities.get(dbKey);

        if(entities!=null){
            for(DBXRefEntity entity : entities){
                if(entity.test(id)){
                    return true;
                }
            }
        }
        return false;
    }

    static class DBXRefEntityAggregator implements ItemWriter<DBXRefEntity> {

        @Override public void write(List<? extends DBXRefEntity> items) throws Exception {

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

@@ -111,16 +111,101 @@
 ntity;%0A%0A
+import com.google.common.base.Function;%0Aimport com.google.common.base.Preconditions;%0A
 import j
@@ -904,24 +904,244 @@
 shMap%3C%3E();%0A%0A
+    private static Function%3CString,String%3E  toDb = (value) -%3E value.substring(0, value.indexOf(%22:%22)).toLowerCase();%0A    private static Function%3CString, String%3E toId = (value) -%3E value.substring(value.indexOf(%22:%22) + 1);%0A%0A
     @Overrid
@@ -1446,16 +1446,29 @@
 tifiers.
+ Can be null.
 %0A     * 
@@ -1938,150 +1938,8 @@
 nal 
-String dbKey = value.substring(0, value.indexOf(%22:%22)).toLowerCase();%0A        final String id = value.substring(value.indexOf(%22:%22)+1);%0A        
 List
@@ -1987,25 +1987,36 @@
 get(
-dbKey
+toDb.apply(value)
 );%0A
-%0A
         
 if(e
@@ -2015,19 +2015,23 @@
     
-if(
+return 
 entities
 !=nu
@@ -2030,376 +2030,398 @@
 ties
+ 
 !=
+ 
 null
-)%7B%0A            for(DBXRefEntity entity : entities)%7B%0A                if(entity.test(id))%7B%0A                    return true;%0A                %7D%0A            %7D%0A        %7D%0A        return false;%0A    %7D%0A%0A    static class DBXRefEntityAggregator implements ItemWriter%3CDBXRefEntity%3E %7B%0A%0A        @Override public void write(List%3C? extends DBXRefEntity%3E items) throws Exception %7B
+ && entities.stream().anyMatch(e -%3E e.test(toId.apply(value)));%0A    %7D%0A%0A    static class DBXRefEntityAggregator implements ItemWriter%3CDBXRefEntity%3E %7B%0A%0A        @Override public void write(List%3C? extends DBXRefEntity%3E items) %7B%0A            Preconditions.checkArgument(items != null, %22The list of DBXRefEntity written to DBXRefEntityAggregator %22 +%0A                    %22cannot be null.%22);
 %0A%0A  

Optimize code with a bit more java 8ness.