package uk.ac.ebi.atlas.search.baseline;

import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import uk.ac.ebi.atlas.model.FactorAcrossExperiments;
import uk.ac.ebi.atlas.model.Profile;
import uk.ac.ebi.atlas.model.experiment.ExperimentType;
import uk.ac.ebi.atlas.model.experiment.baseline.BaselineExpression;
import uk.ac.ebi.atlas.model.experiment.baseline.Factor;
import uk.ac.ebi.atlas.model.experiment.baseline.FactorGroup;
import uk.ac.ebi.atlas.model.experiment.baseline.impl.FactorSet;

import java.util.Map;

public class BaselineExperimentProfile extends Profile<FactorAcrossExperiments, BaselineExpression> implements Comparable<BaselineExperimentProfile> {

    private final FactorGroup filterFactors;

    private final Integer nonFilterFactorsSize;

    private ExperimentType experimentType;

    public BaselineExperimentProfile(BaselineExperimentSlice experimentSlice) {
        super(joinIntoText(experimentSlice.experimentAccession(), experimentSlice.filterFactors()),
                experimentSlice.experimentDisplayName());
        filterFactors = experimentSlice.filterFactors();
        nonFilterFactorsSize = experimentSlice.nonFilterFactors().size();
        experimentType = experimentSlice.getExperimentType();
    }

    @Override
    /**
     * RNA-seq experiments should come before other types of baseline experiments;
     * Within the same experiment type, the experiments with more conditions with expressions in them should come to the top.
     * If the number of conditions with expression is the same, the sorting should be alphabetic - by the experiment display name.
     */
    public int compareTo(BaselineExperimentProfile other) {
        int experimentTypeComparison =
                this.experimentType == other.experimentType ?
                        0 : (this.experimentType == ExperimentType.RNASEQ_MRNA_BASELINE ? -1 : 1);
        int comparison = (other.nonFilterFactorsSize).compareTo(this.nonFilterFactorsSize);
        if (experimentTypeComparison != 0) {
            return experimentTypeComparison;
        } else {
            return (comparison != 0) ? comparison : (this.getName().compareTo(other.getName()));
        }
    }

    @Override
    protected void updateStateAfterAddingExpression(BaselineExpression expression) {
        // used to maintain maxes and mins but it really isn't necessary
    }

    @Override
    public String getName() {
        return joinIntoText(super.getName(), filterFactors);
    }

    private static String joinIntoText(String core, FactorGroup filterFactors) {
        StringBuilder sb = new StringBuilder();
        sb.append(core);
        if (!filterFactors.isEmpty() && !filterFactors.containsOnlyOrganism()) {
            sb.append(" - ").append(factorsAsText(filterFactors));
        }
        return sb.toString();
    }

    static String factorsAsText(Iterable<Factor> factors) {
        if (!factors.iterator().hasNext()) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        for (Factor factor : factors) {
            sb.append(factor.getValue()).append(", ");
        }

        sb.delete(sb.length() - 2, sb.length());
        return sb.toString();
    }

    static String shorten(String name) {
        if (StringUtils.startsWithAny(name,
                new String[]{
                        "Tissues - ",
                        "Cell Type - ",
                        "Cell Lines - ",
                        "Individual - ",
                        "Developmental Stages - ",
                        "Strains - ",
                        "Cultivars - ",
                        "Ecotypes - "})) {
            String shortenName = name.substring(0, name.indexOf("-") + 2);
            return name.replace(shortenName, "");
        } else if (StringUtils.startsWith(name, "Proteomics - Tissues - ")) {
            return name.replace("Proteomics - Tissues - ", "");
        } else {
            return name;
        }
    }

    String getShortName() {
        return joinIntoText(shorten(super.getName()),
                filterFactors.containsOnlyOrganism() ? new FactorSet() : filterFactors
                );
    }

    public String getExperimentType() {
        return experimentType.toString();
    }

    @Override
    public Map<String, String> properties() {
        return ImmutableMap.<String, String>builder()
                .put("id", super.properties().get("id"))
                .put("name", getShortName())
                .put("experimentType", experimentType.toString())
                .build();
    }
}

@@ -749,17 +749,16 @@
 actors;%0A
-%0A
     priv
@@ -794,24 +794,64 @@
 ctorsSize;%0A%0A
+    private String experimentAccession;%0A
     private 
@@ -989,16 +989,33 @@
 ntoText(
+%0A                
 experime
@@ -1044,16 +1044,32 @@
 ssion(),
+%0A               
  experim
@@ -1306,50 +1306,204 @@
 ment
-Type = experimentSlice.getExperimentType()
+Accession = experimentSlice.experimentAccession();%0A        experimentType = experimentSlice.getExperimentType();%0A    %7D%0A%0A    @Override%0A    public String getId() %7B%0A        return experimentAccession
 ;%0A  

Add experimentAccession field to BaselineExperimentProfile to create well-formed URLs in the multiexperiment heatmap links