package uk.ac.ebi.atlas.experimentimport;

import com.atlassian.util.concurrent.LazyReference;
import uk.ac.ebi.atlas.model.AssayGroup;
import uk.ac.ebi.atlas.model.experiment.ExperimentConfiguration;
import uk.ac.ebi.atlas.model.experiment.ExperimentDesign;

import java.text.MessageFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkState;

public class ExperimentFilesCrossValidator {

    private final ExperimentConfiguration experimentConfiguration;
    private final ExperimentDesign experimentDesign;
    private LazyReference<List<AssayGroup>> assayGroups = new LazyReference<List<AssayGroup>>() {
        @Override
        protected List<AssayGroup> create() throws Exception {
            return experimentConfiguration.getAssayGroups();
        }
    };

    public ExperimentFilesCrossValidator(ExperimentConfiguration experimentConfiguration, ExperimentDesign experimentDesign){
        this.experimentConfiguration = experimentConfiguration;
        this.experimentDesign = experimentDesign;
    }


    public void validate() throws IllegalStateException {
        checkState(! assayGroups.get().isEmpty() , "Experiment config appears to be without assay groups!");
        factorsNotMissing();
        sampleCharacteristicsNotMissing();
        factorsConsistentWithinAssay();
    }


    void factorsNotMissing(){
        for(AssayGroup assayGroup: assayGroups.get()){
            for(String assayGroupId: assayGroup.assaysAnalyzedForThisDataColumn()){
                checkState(! experimentDesign.getFactorValues(assayGroupId).isEmpty(),
                        MessageFormat.format("Factor values for assay id {0} missing from experiment design file!",
                                assayGroupId));
            }
        }
    }

    void sampleCharacteristicsNotMissing(){
        for(AssayGroup assayGroup: assayGroups.get()){
            for(String assayGroupId: assayGroup.assaysAnalyzedForThisDataColumn()){
                checkState(! experimentDesign.getSampleCharacteristics(assayGroupId).isEmpty(),
                        MessageFormat.format("Sample characteristics values for assay id {0} missing from experiment design file!",
                                assayGroupId));
            }
        }
    }

    void factorsConsistentWithinAssay(){

        for(AssayGroup assayGroup : assayGroups.get()){
            Set<Set<Map.Entry<String, String>>> factorsPerAssayForThisAssayGroup = new HashSet<>();
            for(String assayGroupId: assayGroup.assaysAnalyzedForThisDataColumn()){
                Map<String, String> factorValues = experimentDesign.getFactorValues(assayGroupId);

                /*
                We allow differential experiments with factor type "block" e.g. E-MTAB-4442.
                They're introduced for the pipeline, to facilitate processing experiments with a particular type of batch effects.
                Differential experiments as of 5 Sep 2017 will work fine without an unambiguous assay group -> factor group mapping.
                We continue to make assertions for differential experiments too - to flag up cases with inconsistent factor values within assay group.
                They're probably not wanted but future developers should feel free to revisit this assertion or remove it.
                 */
                factorsPerAssayForThisAssayGroup.add(factorValues.entrySet().stream().filter(e -> !experimentConfiguration.getExperimentType().isDifferential() || !e.getKey().equals("block")).collect(Collectors.toSet()));
            }
            checkState(factorsPerAssayForThisAssayGroup.size() == 1,
                    MessageFormat.format("Factor values inconsistent across assays in assay group {0}!", assayGroup.getId()));
        }
    }
}

@@ -306,118 +306,12 @@
 til.
-HashSet;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.Set;%0Aimport java.util.stream.Collectors
+List
 ;%0A%0Ai
@@ -1288,48 +1288,8 @@
 ();%0A
-        factorsConsistentWithinAssay();%0A
     
@@ -2194,32 +2194,32 @@
 assayGroupId));%0A
+
             %7D%0A  
@@ -2235,1508 +2235,7 @@
    %7D
-%0A%0A    void factorsConsistentWithinAssay()%7B%0A%0A        for(AssayGroup assayGroup : assayGroups.get())%7B%0A            Set%3CSet%3CMap.Entry%3CString, String%3E%3E%3E factorsPerAssayForThisAssayGroup = new HashSet%3C%3E();%0A            for(String assayGroupId: assayGroup.assaysAnalyzedForThisDataColumn())%7B%0A                Map%3CString, String%3E factorValues = experimentDesign.getFactorValues(assayGroupId);%0A%0A                /*%0A                We allow differential experiments with factor type %22block%22 e.g. E-MTAB-4442.%0A                They're introduced for the pipeline, to facilitate processing experiments with a particular type of batch effects.%0A                Differential experiments as of 5 Sep 2017 will work fine without an unambiguous assay group -%3E factor group mapping.%0A                We continue to make assertions for differential experiments too - to flag up cases with inconsistent factor values within assay group.%0A                They're probably not wanted but future developers should feel free to revisit this assertion or remove it.%0A                 */%0A                factorsPerAssayForThisAssayGroup.add(factorValues.entrySet().stream().filter(e -%3E !experimentConfiguration.getExperimentType().isDifferential() %7C%7C !e.getKey().equals(%22block%22)).collect(Collectors.toSet()));%0A            %7D%0A            checkState(factorsPerAssayForThisAssayGroup.size() == 1,%0A                    MessageFormat.format(%22Factor values inconsistent across assays in assay group %7B0%7D!%22, assayGroup.getId()));%0A        %7D%0A    %7D
 %0A%7D%0A

Remove check that ensures factor values are unique within an assay group Experiments with multiple factor values in the same assay group (e.g. E-GEOD-21912) show up fine in the UI. Confirmed by curators that this is ok.