<commit_before>package uk.ac.ebi.atlas.model.experiment;

import com.google.common.base.Joiner;
import com.google.common.collect.*;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import uk.ac.ebi.atlas.commons.readers.XmlReader;
import uk.ac.ebi.atlas.model.AssayGroup;
import uk.ac.ebi.atlas.model.BiologicalReplicate;
import uk.ac.ebi.atlas.model.experiment.differential.Contrast;

import javax.xml.xpath.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;

public class ExperimentConfiguration {

    private static final String EXPERIMENT_TYPE = "experimentType";

    private XmlReader xmlReader;
    private XPath xpath = XPathFactory.newInstance().newXPath();

    public ExperimentConfiguration(XmlReader xmlReader) {
        this.xmlReader = xmlReader;
    }

    public List<Pair<Contrast, Boolean>> getContrastAndAnnotationPairs() {

        List<Pair<Contrast, Boolean>> contrasts = new ArrayList<>();

        NodeList arrayDesigns = xmlReader.getDocument().getElementsByTagName("array_design");
        for (int i = 0; i < arrayDesigns.getLength(); i++) {
            Node currentArrayDesign = arrayDesigns.item(i);
            String arrayDesignAccession = currentArrayDesign.getFirstChild().getTextContent().trim();
            parseContrastConfiguration("analytics[" + (i + 1) + "]/contrasts/contrast/@id", arrayDesignAccession, contrasts);
        }

        // in case no array designs (case of RNA-seq)
        if (arrayDesigns.getLength() == 0) {
            parseContrastConfiguration("analytics/contrasts/contrast/@id", null, contrasts);
        }

        return contrasts;
    }

    public List<Contrast> getContrasts(){
        return FluentIterable.from(getContrastAndAnnotationPairs()).transform(Pair::getLeft).toList();
    }

    private void parseContrastConfiguration(String query, String arrayDesignAccession, List<Pair<Contrast, Boolean>> contrasts) {
        String[] ids = xmlReader.getStringArray(query);
        for (String id : ids) {
            contrasts.add(getContrastAndCttvPrimaryPair(id, arrayDesignAccession));
        }
    }

    private Pair<Contrast,Boolean> getContrastAndCttvPrimaryPair(String id, String arrayDesignAccession) {
        Configuration configuration = xmlReader.configurationAt("analytics/contrasts/contrast[@id=\'" + id + "\']");
        String name = configuration.getString("name");
        String reference = configuration.getString("reference_assay_group");
        String test = configuration.getString("test_assay_group");

        return Pair.of(new Contrast(id, arrayDesignAccession, getAssayGroup(reference), getAssayGroup(test), name),
                new Integer(1).equals(configuration.getInt("cttv_primary", -1)));
    }

    private AssayGroup getAssayGroup(String id) {
        try {
            XPathExpression expr = xpath.compile("/configuration/analytics/assay_groups/assay_group[@id='" + id + "']/assay");

            NodeList nl = (NodeList) expr.evaluate(xmlReader.getDocument(), XPathConstants.NODESET);

            ImmutableSet.Builder<BiologicalReplicate> biologicalReplicates = ImmutableSet.builder();

            Multimap<String, String> technicalReplicatesPerId = LinkedListMultimap.create();

            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                String technicalReplicateId = getAttribute(node, "technical_replicate_id");
                if (technicalReplicateId != null) {
                    technicalReplicatesPerId.put(technicalReplicateId, node.getTextContent());
                } else {
                    biologicalReplicates.add(new BiologicalReplicate(node.getTextContent()));
                }
            }

            technicalReplicatesPerId.asMap().forEach((biologicalReplicateId, assays) ->
               biologicalReplicates.add(new BiologicalReplicate(biologicalReplicateId, ImmutableSet.copyOf(assays)))
            );
            return new AssayGroup(id,biologicalReplicates.build());

        } catch (XPathExpressionException e) {
            throw new IllegalStateException("Problem parsing configuration file.", e);
        }
    }

    private String getAttribute(Node node, String name) {
        Node attribute = node.getAttributes().getNamedItem(name);
        return (attribute == null) ? null : attribute.getNodeValue();<commit_msg>Fix assumption: a technical replicate can have only one assay<commit_after>package uk.ac.ebi.atlas.model.experiment;

import com.google.common.base.Joiner;
import com.google.common.collect.*;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import uk.ac.ebi.atlas.commons.readers.XmlReader;
import uk.ac.ebi.atlas.model.AssayGroup;
import uk.ac.ebi.atlas.model.BiologicalReplicate;
import uk.ac.ebi.atlas.model.experiment.differential.Contrast;

import javax.xml.xpath.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;

public class ExperimentConfiguration {

    private static final String EXPERIMENT_TYPE = "experimentType";

    private XmlReader xmlReader;
    private XPath xpath = XPathFactory.newInstance().newXPath();

    public ExperimentConfiguration(XmlReader xmlReader) {
        this.xmlReader = xmlReader;
    }

    public List<Pair<Contrast, Boolean>> getContrastAndAnnotationPairs() {

        List<Pair<Contrast, Boolean>> contrasts = new ArrayList<>();

        NodeList arrayDesigns = xmlReader.getDocument().getElementsByTagName("array_design");
        for (int i = 0; i < arrayDesigns.getLength(); i++) {
            Node currentArrayDesign = arrayDesigns.item(i);
            String arrayDesignAccession = currentArrayDesign.getFirstChild().getTextContent().trim();
            parseContrastConfiguration("analytics[" + (i + 1) + "]/contrasts/contrast/@id", arrayDesignAccession, contrasts);
        }

        // in case no array designs (case of RNA-seq)
        if (arrayDesigns.getLength() == 0) {
            parseContrastConfiguration("analytics/contrasts/contrast/@id", null, contrasts);
        }

        return contrasts;
    }

    public List<Contrast> getContrasts(){
        return FluentIterable.from(getContrastAndAnnotationPairs()).transform(Pair::getLeft).toList();
    }

    private void parseContrastConfiguration(String query, String arrayDesignAccession, List<Pair<Contrast, Boolean>> contrasts) {
        String[] ids = xmlReader.getStringArray(query);
        for (String id : ids) {
            contrasts.add(getContrastAndCttvPrimaryPair(id, arrayDesignAccession));
        }
    }

    private Pair<Contrast,Boolean> getContrastAndCttvPrimaryPair(String id, String arrayDesignAccession) {
        Configuration configuration = xmlReader.configurationAt("analytics/contrasts/contrast[@id=\'" + id + "\']");
        String name = configuration.getString("name");
        String reference = configuration.getString("reference_assay_group");
        String test = configuration.getString("test_assay_group");

        return Pair.of(new Contrast(id, arrayDesignAccession, getAssayGroup(reference), getAssayGroup(test), name),
                new Integer(1).equals(configuration.getInt("cttv_primary", -1)));
    }

    private AssayGroup getAssayGroup(String id) {
        try {
            XPathExpression expr = xpath.compile("/configuration/analytics/assay_groups/assay_group[@id='" + id + "']/assay");

            NodeList nl = (NodeList) expr.evaluate(xmlReader.getDocument(), XPathConstants.NODESET);

            ImmutableSet.Builder<BiologicalReplicate> biologicalReplicates = ImmutableSet.builder();

            Multimap<String, String> technicalReplicatesPerId = LinkedListMultimap.create();

            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                String technicalReplicateId = getAttribute(node, "technical_replicate_id");
                if (technicalReplicateId != null) {
                    technicalReplicatesPerId.put(technicalReplicateId, node.getTextContent());
                } else {
                    biologicalReplicates.add(new BiologicalReplicate(node.getTextContent()));
                }
            }

            technicalReplicatesPerId.asMap().forEach((biologicalReplicateId, assays) ->
               biologicalReplicates.add(assays.size() > 1
                       ? new BiologicalReplicate(biologicalReplicateId, ImmutableSet.copyOf(assays))
                       : new BiologicalReplicate(assays.iterator().next()))
            );
            return new AssayGroup(id,biologicalReplicates.build());

        } catch (XPathExpressionException e) {
            throw new IllegalStateException("Problem parsing configuration file.", e);
        }
    }

    private String getAttribute(Node node, String name) {
        Node attribute = node.getAttributes().getNamedItem(name);
        return (attribute == null) ? null : attribute.getNodeValue();
{'fraction_non_alphanumeric': 0.11181661644425311, 'fraction_numerical': 0.0026904864399483427, 'mean_word_length': 3.346585594013096, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1092369', 'n_tokens_mistral': 2648, 'n_tokens_neox': 2503, 'n_words': 476}