<commit_before>package org.mskcc.cbio.oncokb.util;

import org.apache.commons.lang3.StringUtils;
import org.genome_nexus.client.TranscriptConsequenceSummary;
import org.mskcc.cbio.oncokb.bo.AlterationBo;
import org.mskcc.cbio.oncokb.bo.EvidenceBo;
import org.mskcc.cbio.oncokb.genomenexus.GNVariantAnnotationType;
import org.mskcc.cbio.oncokb.model.*;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.mskcc.cbio.oncokb.Constants.*;

/**
 * @author jgao, <NAME>
 */
public final class AlterationUtils {
    private static List<String> oncogenicList = Arrays.asList(new String[]{
        "", Oncogenicity.INCONCLUSIVE.getOncogenic(), Oncogenicity.LIKELY_NEUTRAL.getOncogenic(),
        Oncogenicity.LIKELY.getOncogenic(), Oncogenicity.YES.getOncogenic()});

    private static AlterationBo alterationBo = ApplicationContextSingleton.getAlterationBo();
    private static final String PROTEIN_CHANGE_EXCLUSION_REGEX = "(.*),\\s*(exclude|excluding)(.*)";


    private AlterationUtils() {
        throw new AssertionError();
    }

    public static boolean consequenceRelated(VariantConsequence consequence, VariantConsequence compareTo) {
        if (consequence == null || compareTo == null) {
            return consequence == compareTo;
        }
        if (SPLICE_SITE_VARIANTS.contains(consequence)) {
            return SPLICE_SITE_VARIANTS.contains(compareTo);
        } else {
            return consequence.equals(compareTo);
        }
    }

    public static Set<Alteration> findOverlapAlteration(Set<Alteration> alterations, Gene gene, ReferenceGenome referenceGenome, VariantConsequence consequence, int start, int end) {
        Set<Alteration> overlaps = new HashSet<>();
        for (Alteration alteration : alterations) {
            if (alteration.getGene().equals(gene) && alteration.getConsequence() != null && consequenceRelated(consequence, alteration.getConsequence()) && (referenceGenome == null || alteration.getReferenceGenomes().contains(referenceGenome))) {
                //For alteration without specific position, do not do intersection
                if (start <= AlterationPositionBoundary.START.getValue() || end >= AlterationPositionBoundary.END.getValue()) {
                    if (start >= alteration.getProteinStart()
                        && end <= alteration.getProteinEnd()) {
                        overlaps.add(alteration);
                    }
                } else if (end >= alteration.getProteinStart()
                    && start <= alteration.getProteinEnd()) {
                    //For variant, as long as they are overlapped to each, return the alteration
                    overlaps.add(alteration);
                }
            }
        }
        return overlaps;
    }

    private static Matcher getExclusionCriteriaMatcher(String proteinChange) {
        Pattern exclusionPatter = Pattern.compile("(.*)\\{\\s*(exclude|excluding)(.*)\\}", Pattern.CASE_INSENSITIVE);
        Matcher exclusionMatch = exclusionPatter.matcher(proteinChange);
        return exclusionMatch;
    }

    public static Set<Alteration> getExclusionAlterations(String proteinChange) {
        Set<Alteration> exclusionAlterations = new HashSet<>();
        Matcher exclusionMatcher = getExclusionCriteriaMatcher(proteinChange);
        if (exclusionMatcher.matches()) {
            String excludedStr = exclusionMatcher.group(3).trim();
            exclusionAlterations.addAll(parseMutationString(excludedStr, ";"));
        }
        return exclusionAlterations;
    }

    public static boolean hasExclusionCriteria(String proteinChange) {
        Matcher exclusionMatch = getExclusionCriteriaMatcher(proteinChange);
        return exclusionMatch.matches();
    }

    public static List<Alteration> parseMutationString(String mutationStr, String mutationSeparator) {
        List<Alteration> ret = new ArrayList<>();

        mutationStr = mutationStr.replaceAll("\\([^\\)]+\\)", ""); // remove comments first

        String[] parts = mutationStr.split(mutationSeparator);

        Pattern p = Pattern.compile("([A-Z][0-9]+)([^0-9/]+/.+)", Pattern.CASE_INSENSITIVE);
        Pattern rgp = Pattern.compile("(((grch37)|(grch38)):\\s*).*", Pattern.CASE_INSENSITIVE);
        for (String part : parts) {
            String proteinChange, displayName;
            part = part.trim();

            Matcher rgm = rgp.matcher(part);
            Set<ReferenceGenome> referenceGenomes = new HashSet<>();
            if (rgm.find()) {
                String referenceGenome = rgm.group(2);
                ReferenceGenome matchedReferenceGenome = MainUtils.searchEnum(ReferenceGenome.class, referenceGenome);
                if (matchedReferenceGenome != null) {
                    referenceGenomes.add(matchedReferenceGenome);
                }
                part = part.replace(rgm.group(1), "");
            } else {
                referenceGenomes.add(ReferenceGenome.GRCh37);
                referenceGenomes.add(ReferenceGenome.GRCh38);
            }

            if (part.contains("[")) {
                int l = part.indexOf("[");
                int r = part.indexOf("]");
                proteinChange = part.substring(0, l).trim();
                displayName = part.substring(l + 1, r).trim();
            } else {
                proteinChange = part;
                displayName = part;
                if (displayName.contains("{")) {
                    int left = displayName.indexOf("{");
                    int right = displayName.indexOf("}");
                    if (left > 0 && right > 0) {
                        String exclusion = displayName.substring(left + 1, right);
                        String separatorRegex = "\\s*;\\s*";
                        exclusion = MainUtils.replaceLast(exclusion, separatorRegex, " and ");
                        exclusion = exclusion.replaceAll(separatorRegex, ", ");

                        displayName = displayName.substring(0, left) + "(" + exclusion + ")" + displayName.substring(right + 1);
                    }
                }
            }

            Matcher m = p.matcher(proteinChange);
            if (m.find()) {
                String ref = m.group(1);
                for (String var : m.group(2).split("/")) {
                    Alteration alteration = new Alteration();
                    alteration.setAlteration(ref + var);
                    alteration.setName(ref + var);
                    alteration.setReferenceGenomes(referenceGenomes);
                    ret.add(alteration);
                }
            } else {
                Alteration alteration = new Alteration();
                alteration.setAlteration(proteinChange);
                alteration.setName(displayName);
                alteration.setReferenceGenomes(referenceGenomes);
                ret.add(alteration);
            }
        }
        return ret;
    }

    public static void annotateAlteration(Alteration alteration, String proteinChange) {
        String consequence = "NA";
        String ref = null;
        String var = null;
        Integer start = AlterationPositionBoundary.START.getValue();
        Integer end = AlterationPositionBoundary.END.getValue();

        if (alteration == null) {<commit_msg>Fix issue the parenthesis in curly curly brackets is identified as comment<commit_after>package org.mskcc.cbio.oncokb.util;

import org.apache.commons.lang3.StringUtils;
import org.genome_nexus.client.TranscriptConsequenceSummary;
import org.mskcc.cbio.oncokb.bo.AlterationBo;
import org.mskcc.cbio.oncokb.bo.EvidenceBo;
import org.mskcc.cbio.oncokb.genomenexus.GNVariantAnnotationType;
import org.mskcc.cbio.oncokb.model.*;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.mskcc.cbio.oncokb.Constants.*;

/**
 * @author jgao, <NAME>
 */
public final class AlterationUtils {
    private static List<String> oncogenicList = Arrays.asList(new String[]{
        "", Oncogenicity.INCONCLUSIVE.getOncogenic(), Oncogenicity.LIKELY_NEUTRAL.getOncogenic(),
        Oncogenicity.LIKELY.getOncogenic(), Oncogenicity.YES.getOncogenic()});

    private static AlterationBo alterationBo = ApplicationContextSingleton.getAlterationBo();
    private static final String PROTEIN_CHANGE_EXCLUSION_REGEX = "(.*),\\s*(exclude|excluding)(.*)";


    private AlterationUtils() {
        throw new AssertionError();
    }

    public static boolean consequenceRelated(VariantConsequence consequence, VariantConsequence compareTo) {
        if (consequence == null || compareTo == null) {
            return consequence == compareTo;
        }
        if (SPLICE_SITE_VARIANTS.contains(consequence)) {
            return SPLICE_SITE_VARIANTS.contains(compareTo);
        } else {
            return consequence.equals(compareTo);
        }
    }

    public static Set<Alteration> findOverlapAlteration(Set<Alteration> alterations, Gene gene, ReferenceGenome referenceGenome, VariantConsequence consequence, int start, int end) {
        Set<Alteration> overlaps = new HashSet<>();
        for (Alteration alteration : alterations) {
            if (alteration.getGene().equals(gene) && alteration.getConsequence() != null && consequenceRelated(consequence, alteration.getConsequence()) && (referenceGenome == null || alteration.getReferenceGenomes().contains(referenceGenome))) {
                //For alteration without specific position, do not do intersection
                if (start <= AlterationPositionBoundary.START.getValue() || end >= AlterationPositionBoundary.END.getValue()) {
                    if (start >= alteration.getProteinStart()
                        && end <= alteration.getProteinEnd()) {
                        overlaps.add(alteration);
                    }
                } else if (end >= alteration.getProteinStart()
                    && start <= alteration.getProteinEnd()) {
                    //For variant, as long as they are overlapped to each, return the alteration
                    overlaps.add(alteration);
                }
            }
        }
        return overlaps;
    }

    private static Matcher getExclusionCriteriaMatcher(String proteinChange) {
        Pattern exclusionPatter = Pattern.compile("(.*)\\{\\s*(exclude|excluding)(.*)\\}", Pattern.CASE_INSENSITIVE);
        Matcher exclusionMatch = exclusionPatter.matcher(proteinChange);
        return exclusionMatch;
    }

    public static Set<Alteration> getExclusionAlterations(String proteinChange) {
        Set<Alteration> exclusionAlterations = new HashSet<>();
        Matcher exclusionMatcher = getExclusionCriteriaMatcher(proteinChange);
        if (exclusionMatcher.matches()) {
            String excludedStr = exclusionMatcher.group(3).trim();
            exclusionAlterations.addAll(parseMutationString(excludedStr, ";"));
        }
        return exclusionAlterations;
    }

    public static boolean hasExclusionCriteria(String proteinChange) {
        Matcher exclusionMatch = getExclusionCriteriaMatcher(proteinChange);
        return exclusionMatch.matches();
    }

    private static String trimComment(String mutationStr) {
        if (StringUtils.isEmpty(mutationStr)) {
            return "";
        }
        mutationStr = mutationStr.trim();
        if (mutationStr.endsWith(")")) {
            int commentStartIndex = mutationStr.lastIndexOf("(");
            mutationStr = mutationStr.substring(0, commentStartIndex);
        }
        return mutationStr.trim();
    }

    public static List<Alteration> parseMutationString(String mutationStr, String mutationSeparator) {
        List<Alteration> ret = new ArrayList<>();

        mutationStr = trimComment(mutationStr);

        String[] parts = mutationStr.split(mutationSeparator);

        Pattern p = Pattern.compile("([A-Z][0-9]+)([^0-9/]+/.+)", Pattern.CASE_INSENSITIVE);
        Pattern rgp = Pattern.compile("(((grch37)|(grch38)):\\s*).*", Pattern.CASE_INSENSITIVE);
        for (String part : parts) {
            String proteinChange, displayName;
            part = part.trim();

            Matcher rgm = rgp.matcher(part);
            Set<ReferenceGenome> referenceGenomes = new HashSet<>();
            if (rgm.find()) {
                String referenceGenome = rgm.group(2);
                ReferenceGenome matchedReferenceGenome = MainUtils.searchEnum(ReferenceGenome.class, referenceGenome);
                if (matchedReferenceGenome != null) {
                    referenceGenomes.add(matchedReferenceGenome);
                }
                part = part.replace(rgm.group(1), "");
            } else {
                referenceGenomes.add(ReferenceGenome.GRCh37);
                referenceGenomes.add(ReferenceGenome.GRCh38);
            }

            if (part.contains("[")) {
                int l = part.indexOf("[");
                int r = part.indexOf("]");
                proteinChange = part.substring(0, l).trim();
                displayName = part.substring(l + 1, r).trim();
            } else {
                proteinChange = part;
                displayName = part;
                if (displayName.contains("{")) {
                    int left = displayName.indexOf("{");
                    int right = displayName.indexOf("}");
                    if (left > 0 && right > 0) {
                        String exclusion = displayName.substring(left + 1, right);
                        String separatorRegex = "\\s*;\\s*";
                        exclusion = MainUtils.replaceLast(exclusion, separatorRegex, " and ");
                        exclusion = exclusion.replaceAll(separatorRegex, ", ");

                        displayName = displayName.substring(0, left) + "(" + exclusion + ")" + displayName.substring(right + 1);
                    }
                }
            }
            proteinChange = trimComment(proteinChange);

            Matcher m = p.matcher(proteinChange);
            if (m.find()) {
                String ref = m.group(1);
                for (String var : m.group(2).split("/")) {
                    Alteration alteration = new Alteration();
                    alteration.setAlteration(ref + var);
                    alteration.setName(ref + var);
                    alteration.setReferenceGenomes(referenceGenomes);
                    ret.add(alteration);
                }
            } else {
                Alteration alteration = new Alteration();
                alteration.setAlteration(proteinChange);
                alteration.setName(displayName);
                alteration.setReferenceGenomes(referenceGenomes);
                ret.add(alteration);
            }
        }
        return ret;
    }

    public static void annotateAlteration(Alteration alteration, String proteinChange) {
        String consequence = "NA";
        String ref = null;
        String var = null;
        Integer start = AlterationPositionBoundary.START.getValue();
        Integer end = AlterationPositionBoundary.END.getValue();

        if (alteration == null) {
{'fraction_non_alphanumeric': 0.11092014806980434, 'fraction_numerical': 0.0033712321523003703, 'mean_word_length': 2.28748370273794, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 41, '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': '5107372', 'n_tokens_mistral': 4186, 'n_tokens_neox': 3868, 'n_words': 770}