<commit_before>package org.opencb.opencga.storage.hadoop.variant.archive.mr;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opencb.biodata.models.variant.StudyEntry;
import org.opencb.biodata.models.variant.Variant;
import org.opencb.biodata.models.variant.VariantVcfFactory;
import org.opencb.biodata.models.variant.avro.AlternateCoordinate;
import org.opencb.biodata.models.variant.avro.FileEntry;
import org.opencb.biodata.models.variant.avro.VariantType;
import org.opencb.opencga.storage.hadoop.variant.index.VariantTableStudyRow;

import java.util.*;
import java.util.stream.Collectors;

import static htsjdk.variant.vcf.VCFConstants.GENOTYPE_FILTER_KEY;
import static htsjdk.variant.vcf.VCFConstants.GENOTYPE_KEY;
import static org.opencb.biodata.models.variant.VariantVcfFactory.FILTER;
import static org.opencb.biodata.models.variant.VariantVcfFactory.QUAL;
import static org.opencb.biodata.models.variant.avro.VariantType.NO_VARIATION;

/**
 * Created by mh719 on 10/06/2016.
 */
public class VariantLocalConflictResolver {


    private VariantPositionRefAltComparator POS_REF_ALT_COMP = new VariantPositionRefAltComparator();
    public List<Variant> resolveConflicts(List<Variant> variants) {
        // sorted by position assumed
        List<Variant> varSorted = new ArrayList<>(variants);
        Collections.sort(varSorted, POS_REF_ALT_COMP);
        List<Variant> resolved = new ArrayList<>(variants.size());
        List<Variant> currVariants = new ArrayList<>();
        for (Variant var : varSorted) {
            if (currVariants.isEmpty()) { // init
                currVariants.add(var);
            } else if (!VariantLocalConflictResolver.hasAnyConflictOverlapInclSecAlt(currVariants, var)) { // no overlap
                resolved.addAll(resolve(currVariants));
                currVariants.clear();
                currVariants.add(var);
            } else { // partial or full overlap
                currVariants.add(var);
            }
        }
        resolved.addAll(resolve(currVariants));
        return resolved;
    }

    /**
     * Returns a nonredudant set of variants, where each position of the genome is only covered once.<br>
     * Conflicting regions are converted as NO_VARIATION.
     *
     * @param conflicts List of Variants with conflicts.
     * @return List of Variants
     */
    public List<Variant> resolve(List<Variant> conflicts) {
        if (conflicts.size() < 2) {
            return conflicts;
        }
        // <start,end> pair stream
        List<Pair<Integer, Integer>> secAltPairs = buildRegions(conflicts);

        int min = secAltPairs.stream().mapToInt(p -> p.getLeft()).min().getAsInt();
        int max = secAltPairs.stream().mapToInt(p -> p.getRight()).max().getAsInt();

        List<Variant> sorted = new ArrayList<>(conflicts);
        sorted.sort(VARIANT_COMP);
        List<Variant> resolved = new ArrayList<>();
        List<Variant> misfit = new ArrayList<>();
        for (Variant q : sorted) {
            if (resolved.isEmpty()) {
                resolved.add(q);
            } else {
                if (!hasAnyConflictOverlapInclSecAlt(resolved, q)) {
                    resolved.add(q);
                } else if (allSameTypeAndGT(resolved, q, VariantType.NO_VARIATION)) {
                    List<Variant> collect = resolved.stream().filter(r -> r.overlapWith(q, true))
                            .collect(Collectors.toList());
                    if (collect.size() != 1) {
                        throw new IllegalStateException("Found " + collect.size() + " overlapping variants for " + q);
                    }
                    Variant variant = collect.get(0);
                    variant.setStart(Math.min(variant.getStart(), q.getStart()));
                    variant.setEnd(Math.max(variant.getEnd(), q.getEnd()));
                    variant.setLength((variant.getEnd() - variant.getStart()) + 1);
                } else {
                    // does not fit
                    misfit.add(q);
                }
            }
        }
        if (!misfit.isEmpty()) {
            // fit into place (before and after)<commit_msg>hadoop: merge conflicting NO_VARIANT regions<commit_after>package org.opencb.opencga.storage.hadoop.variant.archive.mr;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opencb.biodata.models.variant.StudyEntry;
import org.opencb.biodata.models.variant.Variant;
import org.opencb.biodata.models.variant.VariantVcfFactory;
import org.opencb.biodata.models.variant.avro.AlternateCoordinate;
import org.opencb.biodata.models.variant.avro.FileEntry;
import org.opencb.biodata.models.variant.avro.VariantType;
import org.opencb.opencga.storage.hadoop.variant.index.VariantTableStudyRow;

import java.util.*;
import java.util.stream.Collectors;

import static htsjdk.variant.vcf.VCFConstants.GENOTYPE_FILTER_KEY;
import static htsjdk.variant.vcf.VCFConstants.GENOTYPE_KEY;
import static org.opencb.biodata.models.variant.VariantVcfFactory.FILTER;
import static org.opencb.biodata.models.variant.VariantVcfFactory.QUAL;
import static org.opencb.biodata.models.variant.avro.VariantType.NO_VARIATION;

/**
 * Created by mh719 on 10/06/2016.
 */
public class VariantLocalConflictResolver {


    private VariantPositionRefAltComparator POS_REF_ALT_COMP = new VariantPositionRefAltComparator();
    public List<Variant> resolveConflicts(List<Variant> variants) {
        // sorted by position assumed
        List<Variant> varSorted = new ArrayList<>(variants);
        Collections.sort(varSorted, POS_REF_ALT_COMP);
        List<Variant> resolved = new ArrayList<>(variants.size());
        List<Variant> currVariants = new ArrayList<>();
        for (Variant var : varSorted) {
            if (currVariants.isEmpty()) { // init
                currVariants.add(var);
            } else if (!VariantLocalConflictResolver.hasAnyConflictOverlapInclSecAlt(currVariants, var)) { // no overlap
                resolved.addAll(resolve(currVariants));
                currVariants.clear();
                currVariants.add(var);
            } else { // partial or full overlap
                currVariants.add(var);
            }
        }
        resolved.addAll(resolve(currVariants));
        return resolved;
    }

    /**
     * Returns a nonredudant set of variants, where each position of the genome is only covered once.<br>
     * Conflicting regions are converted as NO_VARIATION.
     *
     * @param conflicts List of Variants with conflicts.
     * @return List of Variants
     */
    public List<Variant> resolve(List<Variant> conflicts) {
        if (conflicts.size() < 2) {
            return conflicts;
        }
        // <start,end> pair stream
        List<Pair<Integer, Integer>> secAltPairs = buildRegions(conflicts);

        int min = secAltPairs.stream().mapToInt(p -> p.getLeft()).min().getAsInt();
        int max = secAltPairs.stream().mapToInt(p -> p.getRight()).max().getAsInt();

        List<Variant> sorted = new ArrayList<>(conflicts);
        sorted.sort(VARIANT_COMP);
        List<Variant> resolved = new ArrayList<>();
        List<Variant> misfit = new ArrayList<>();
        for (Variant q : sorted) {
            if (resolved.isEmpty()) {
                resolved.add(q);
            } else {
                if (!hasAnyConflictOverlapInclSecAlt(resolved, q)) {
                    resolved.add(q);
                } else if (allSameTypeAndGT(resolved, q, VariantType.NO_VARIATION)) {
                    List<Variant> collect = resolved.stream().filter(r -> r.overlapWith(q, true))
                            .collect(Collectors.toList());
                    collect.add(q);
                    List<Pair<Integer, Integer>> pairs = buildRegions(collect);
                    collect.sort(varPositionOrder);
                    Variant variant = collect.get(0);
                    int minPos = pairs.stream().mapToInt(p -> p.getLeft()).min().getAsInt();
                    if (!variant.getStart().equals(minPos)) {
                        throw new IllegalStateException("Sorting and merging of NO_VARIATOIN regions went wrong: " + q);
                    }
                    variant.setEnd(pairs.stream().mapToInt(p -> p.getRight()).max().getAsInt());
                    variant.setLength((variant.getEnd() - variant.getStart()) + 1);
                } else {
                    // does not fit
                    misfit.add(q);
                }
            }
        }
        if (!misfit.isEmpty()) {
            // fit into place (before and after)
{'fraction_non_alphanumeric': 0.11554145899410966, 'fraction_numerical': 0.004191209787041232, 'mean_word_length': 2.469155206286837, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '4363299', 'n_tokens_mistral': 2601, 'n_tokens_neox': 2497, 'n_words': 475}