<commit_before>package org.opencb.commons.bioformats.alignment;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import net.sf.samtools.*;
import org.opencb.commons.bioformats.feature.Region;
import org.opencb.commons.containers.map.QueryOptions;

/**
 *
 * @author <NAME> <NAME> <<EMAIL>>
 */
public class AlignmentHelper {



    /**
     * Given a cigar string, returns a list of alignment differences with 
     * the reference sequence.
     *
     * @param record The input cigar string
     * @param refStr reference sequence. It can be null if it is not needed.
     * @param maxStoredSequence Max length for stored sequences. Default = 30
     * @return The list of alignment differences
     */
    public static List<Alignment.AlignmentDifference> getDifferencesFromCigar(SAMRecord record, String refStr, int maxStoredSequence) {
        List<Alignment.AlignmentDifference> differences = new LinkedList<>();

        int index = 0, indexRef = 0, indexMismatchBlock = 0, realStart;
        AlignmentBlock blk;
//        System.out.println("align start = " + record.getAlignmentStart() + 
//                "\t1st block start = " + record.getAlignmentBlocks().get(0).getReferenceStart() + 
//                "\n*****\n" + refStr + "\n" + record.getReadString());

        for (CigarElement element : record.getCigar().getCigarElements()) {
            int cigarLen = element.getLength();
            String subref = null, subread = null;
            Alignment.AlignmentDifference currentDifference = null;

            switch (element.getOperator()) {
                case M:
                case EQ:
                    blk = record.getAlignmentBlocks().get(indexMismatchBlock);
                    realStart = blk.getReferenceStart() - record.getAlignmentStart();
                    // Picard ignores hard clipping, the indices could be necessary
                    indexRef = realStart >= indexRef ? realStart : indexRef;
                    if (refStr != null) {
                        subref = refStr.substring(indexRef, indexRef + blk.getLength());
                        subread = record.getReadString().substring(index, Math.min(index + blk.getLength(), record.getReadString().length()));
                        differences.addAll(getMismatchDiff(subref, subread, indexRef));
                    }
                    index = index + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexRef = indexRef + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexMismatchBlock++;
                    break;
                case X:
                    blk = record.getAlignmentBlocks().get(indexMismatchBlock);
                    realStart = blk.getReferenceStart() - record.getAlignmentStart();
                    // Picard ignores hard clipping, the indices could be necessary
                    indexRef = realStart >= indexRef ? realStart : indexRef;
                    if (refStr == null) {
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.MISMATCH, cigarLen);
                    } else {
                        subref = refStr.substring(indexRef, indexRef + blk.getLength());
                        subread = record.getReadString().substring(index, Math.min(index + blk.getLength(), record.getReadString().length()));
                        differences.addAll(getMismatchDiff(subref, subread, indexRef));
                    }
                    index = index + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexRef = indexRef + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexMismatchBlock++;
                    break;
                case I:
                    if (cigarLen < maxStoredSequence) {
                        subread = record.getReadString().substring(index, index + cigarLen);
                    } else { // Get only first 30 characters in the sequence to copy
                         subread = record.getReadString().substring(index, index + maxStoredSequence-3).concat("...");
                    }
                    currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.INSERTION, subread, cigarLen);
                    index = index + cigarLen;
                    break;
                case D:
                    if (refStr == null) {
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.DELETION, cigarLen);
                    } else {
                        if (cigarLen < maxStoredSequence) {
                            subref = refStr.substring(indexRef, indexRef + cigarLen);
                        } else { // Get only first 30 characters in the sequence to copy
                            subref = refStr.substring(indexRef, indexRef + maxStoredSequence-3).concat("...");
                        }
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.DELETION, subref, cigarLen);
                    }
                    indexRef = indexRef + cigarLen;
                    break;
                case N:<commit_msg>Bug fix on getDifferenceFromCigar when refSeq is null<commit_after>package org.opencb.commons.bioformats.alignment;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import net.sf.samtools.*;
import org.opencb.commons.bioformats.feature.Region;
import org.opencb.commons.containers.map.QueryOptions;

/**
 *
 * @author <NAME> <NAME> <<EMAIL>>
 */
public class AlignmentHelper {



    /**
     * Given a cigar string, returns a list of alignment differences with 
     * the reference sequence.
     *
     * If the reference sequence is null, M tags in the CIGAR can't be assumed to be
     * correct, so they will be stored as mismatches.
     *
     *
     * @param record The input cigar string
     * @param refStr reference sequence.
     * @param maxStoredSequence Max length for stored sequences. Default = 30
     * @return The list of alignment differences
     */
    public static List<Alignment.AlignmentDifference> getDifferencesFromCigar(SAMRecord record, String refStr, int maxStoredSequence) {
        List<Alignment.AlignmentDifference> differences = new LinkedList<>();

        int index = 0, indexRef = 0, indexMismatchBlock = 0, realStart;
        AlignmentBlock blk;
//        System.out.println("align start = " + record.getAlignmentStart() + 
//                "\t1st block start = " + record.getAlignmentBlocks().get(0).getReferenceStart() + 
//                "\n*****\n" + refStr + "\n" + record.getReadString());

        for (CigarElement element : record.getCigar().getCigarElements()) {
            int cigarLen = element.getLength();
            String subref = null, subread = null;
            Alignment.AlignmentDifference currentDifference = null;

            switch (element.getOperator()) {
                case EQ:
                    blk = record.getAlignmentBlocks().get(indexMismatchBlock);
                    realStart = blk.getReferenceStart() - record.getAlignmentStart();
                    // Picard ignores hard clipping, the indices could be necessary
                    indexRef = realStart >= indexRef ? realStart : indexRef;

                    index = index + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexRef = indexRef + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexMismatchBlock++;
                    break;
                case M:
                case X:
                    blk = record.getAlignmentBlocks().get(indexMismatchBlock);
                    realStart = blk.getReferenceStart() - record.getAlignmentStart();
                    // Picard ignores hard clipping, the indices could be necessary
                    indexRef = realStart >= indexRef ? realStart : indexRef;
                    if (refStr == null) {
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.MISMATCH, cigarLen);
                    } else {
                        subref = refStr.substring(indexRef, indexRef + blk.getLength());
                        subread = record.getReadString().substring(index, Math.min(index + blk.getLength(), record.getReadString().length()));
                        differences.addAll(getMismatchDiff(subref, subread, indexRef));
                    }
                    index = index + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexRef = indexRef + record.getAlignmentBlocks().get(indexMismatchBlock).getLength();
                    indexMismatchBlock++;
                    break;
                case I:
                    if (cigarLen < maxStoredSequence) {
                        subread = record.getReadString().substring(index, index + cigarLen);
                    } else { // Get only first 30 characters in the sequence to copy
                        subread = record.getReadString().substring(index, index + maxStoredSequence-3).concat("...");
                    }
                    currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.INSERTION, subread, cigarLen);
                    index = index + cigarLen;
                    break;
                case D:
                    if (refStr == null) {
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.DELETION, cigarLen);
                    } else {
                        if (cigarLen < maxStoredSequence) {
                            subref = refStr.substring(indexRef, indexRef + cigarLen);
                        } else { // Get only first 30 characters in the sequence to copy
                            subref = refStr.substring(indexRef, indexRef + maxStoredSequence-3).concat("...");
                        }
                        currentDifference = new Alignment.AlignmentDifference(indexRef, Alignment.AlignmentDifference.DELETION, subref, cigarLen);
                    }
                    indexRef = indexRef + cigarLen;
                    break;
                case N:
{'fraction_non_alphanumeric': 0.0952808988764045, 'fraction_numerical': 0.0023370786516853934, 'mean_word_length': 2.011911207363292, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, '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': '7664242', 'n_tokens_mistral': 2887, 'n_tokens_neox': 2664, 'n_words': 632}