# Path: mirtop/mirna/realign.py
# class hits:
#     """"Class with alignment information."""
# 
#     def __init__(self):
#         self.sequence = ""
#         self.idseq = ""
#         self.precursors = defaultdict(isomir)
#         self.score = []
#         self.best_hits = []  # maybe sam object?
#         self.counts = 0
# 
#     def set_sequence(self, seq):
#         self.sequence = seq
#         self.idseq = make_id(seq)
# 
#     def set_precursor(self, precursor, isomir):
#         self.precursors[(precursor, isomir.start)] = isomir
# 
#     def remove_precursor(self, precursor):
#         del self.precursors[precursor]
# 
# def cigar_correction(cigarLine, query, target):
#     """
#     Read from CIGAR in BAM file to define mismatches.
# 
#     Args:
#         *cirgarLine(str)*: CIGAR string from BAM file.
# 
#         *query(str)*: read sequence.
# 
#         *target(str)*: target sequence.
# 
#     Returns:
#         *(list)*: [query_nts, target_nts]
#     """
#     query_pos = 0
#     target_pos = 0
#     query_fixed = []
#     target_fixed = []
#     for (cigarType, cigarLength) in cigarLine:
#         if cigarType == 0:  # match
#             query_fixed.append(query[query_pos:query_pos+cigarLength])
#             target_fixed.append(target[target_pos:target_pos+cigarLength])
#             query_pos = query_pos + cigarLength
#             target_pos = target_pos + cigarLength
#         elif cigarType == 1:  # insertions
#             query_fixed.append(query[query_pos:query_pos+cigarLength])
#             target_fixed.append("".join(["-"] * cigarLength))
#             query_pos = query_pos + cigarLength
#         elif cigarType == 2:  # deletion
#             target_fixed.append(target[target_pos:target_pos+cigarLength])
#             query_fixed.append("".join(["-"] * cigarLength))
#             target_pos = target_pos + cigarLength
#     return ["".join(query_fixed), "".join(target_fixed)]
# 
# def make_cigar(seq, mature):
#     """
#     Function that will create CIGAR string from aligment
#     between read and reference sequence.
# 
#     Args:
#         *seq(str)*: read sequence.
# 
#         *mature(str)*: short sequence.
# 
#     Return:
#         *short(str)*: CIGAR string.
#     """
#     cigar = ""
#     for pos in range(0, len(seq)):
#         if seq[pos] == mature[pos]:
#             cigar += "M"
#         elif seq[pos] != mature[pos] and seq[pos] != "-" and mature[pos] != "-":
#             cigar += seq[pos]
#         elif seq[pos] == "-":
#             cigar += "D"
#         elif mature[pos] == "-":
#             cigar += "I"
# 
#     cache = ""
#     counter = 1
#     short = ""
#     for c in cigar:
#         if c != cache and cache != "" and cache == "M":
#             short += _add_cigar_char(counter, cache)
#             counter = 1
#             cache = c
#         if c != "M":
#             short += c
#         if c == cache and c == "M":
#             counter += 1
#         cache = c
# 
#     if cache == "M":
#         short += _add_cigar_char(counter, cache)
#     return short
# 
# def align(x, y, local=False):
#     """
#     Pairwise alignments between two sequenes.
#     https://medium.com/towards-data-science/pairwise-sequence-alignment-using-biopython-d1a9d0ba861f
# 
#     Args:
#         *x(str)*: short sequence.
# 
#         *y(str)*: long sequence.
# 
#         *local(boolean)*: local or global alignment.
# 
#     Returns:
#         *aligned_x(hit)*: alignment information, socre and positions.
#     """
#     if local:
#         aligned_x = pairwise2.align.localxx(x, y)[0]
#     else:
#         aligned_x = pairwise2.align.globalms(x, y, 1, -1, -1, -0.5)[0]
#     aligned_x = list(aligned_x)
#     n_x = aligned_x[0]
#     if "N" in n_x:
#         N_indices = [i for i, ltr in enumerate(n_x) if ltr == 'N']
#         n_x = list(n_x)
#         for N_index in N_indices:
#             n_x[N_index] = y[N_index]
#         n_x = ''.join(n_x)
# 
#     aligned_x[0] = n_x
#     return tuple(aligned_x)


from collections import defaultdict
from mirtop.mirna.realign import hits, cigar_correction, make_cigar, align
import mirtop.libs.logger as mylog
                    add_position.pop()
                if prob == 0:
                    add = []
                    add_position = []
                break

    for e in error:
        if e not in add_position:
            subs.append([e, seq[e], mature[e]])
    if not error:
        add = []
    
    logger.debug("TUNE:: %s %s" % (subs, add))
    
    return subs, "".join(add), make_cigar(seq, mature)


def clean_hits(reads):
    """
    Select only best matches from a list of hits from the same read.

    Args:
        *reads*: dictionary as:

        >>> {'read_id': mirtop.realign.hits, ...}

    Returns:

        *reads*: same than input but with best hits only.
    """

# Path: mirtop/mirna/realign.py
# class hits:
#     """"Class with alignment information."""
# 
#     def __init__(self):
#         self.sequence = ""
#         self.idseq = ""
#         self.precursors = defaultdict(isomir)
#         self.score = []
#         self.best_hits = []  # maybe sam object?
#         self.counts = 0
# 
#     def set_sequence(self, seq):
#         self.sequence = seq
#         self.idseq = make_id(seq)
# 
#     def set_precursor(self, precursor, isomir):
#         self.precursors[(precursor, isomir.start)] = isomir
# 
#     def remove_precursor(self, precursor):
#         del self.precursors[precursor]
# 
# def cigar_correction(cigarLine, query, target):
#     """
#     Read from CIGAR in BAM file to define mismatches.
# 
#     Args:
#         *cirgarLine(str)*: CIGAR string from BAM file.
# 
#         *query(str)*: read sequence.
# 
#         *target(str)*: target sequence.
# 
#     Returns:
#         *(list)*: [query_nts, target_nts]
#     """
#     query_pos = 0
#     target_pos = 0
#     query_fixed = []
#     target_fixed = []
#     for (cigarType, cigarLength) in cigarLine:
#         if cigarType == 0:  # match
#             query_fixed.append(query[query_pos:query_pos+cigarLength])
#             target_fixed.append(target[target_pos:target_pos+cigarLength])
#             query_pos = query_pos + cigarLength
#             target_pos = target_pos + cigarLength
#         elif cigarType == 1:  # insertions
#             query_fixed.append(query[query_pos:query_pos+cigarLength])
#             target_fixed.append("".join(["-"] * cigarLength))
#             query_pos = query_pos + cigarLength
#         elif cigarType == 2:  # deletion
#             target_fixed.append(target[target_pos:target_pos+cigarLength])
#             query_fixed.append("".join(["-"] * cigarLength))
#             target_pos = target_pos + cigarLength
#     return ["".join(query_fixed), "".join(target_fixed)]
# 
# def make_cigar(seq, mature):
#     """
#     Function that will create CIGAR string from aligment
#     between read and reference sequence.
# 
#     Args:
#         *seq(str)*: read sequence.
# 
#         *mature(str)*: short sequence.
# 
#     Return:
#         *short(str)*: CIGAR string.
#     """
#     cigar = ""
#     for pos in range(0, len(seq)):
#         if seq[pos] == mature[pos]:
#             cigar += "M"
#         elif seq[pos] != mature[pos] and seq[pos] != "-" and mature[pos] != "-":
#             cigar += seq[pos]
#         elif seq[pos] == "-":
#             cigar += "D"
#         elif mature[pos] == "-":
#             cigar += "I"
# 
#     cache = ""
#     counter = 1
#     short = ""
#     for c in cigar:
#         if c != cache and cache != "" and cache == "M":
#             short += _add_cigar_char(counter, cache)
#             counter = 1
#             cache = c
#         if c != "M":
#             short += c
#         if c == cache and c == "M":
#             counter += 1
#         cache = c
# 
#     if cache == "M":
#         short += _add_cigar_char(counter, cache)
#     return short
# 
# def align(x, y, local=False):
#     """
#     Pairwise alignments between two sequenes.
#     https://medium.com/towards-data-science/pairwise-sequence-alignment-using-biopython-d1a9d0ba861f
# 
#     Args:
#         *x(str)*: short sequence.
# 
#         *y(str)*: long sequence.
# 
#         *local(boolean)*: local or global alignment.
# 
#     Returns:
#         *aligned_x(hit)*: alignment information, socre and positions.
#     """
#     if local:
#         aligned_x = pairwise2.align.localxx(x, y)[0]
#     else:
#         aligned_x = pairwise2.align.globalms(x, y, 1, -1, -1, -0.5)[0]
#     aligned_x = list(aligned_x)
#     n_x = aligned_x[0]
#     if "N" in n_x:
#         N_indices = [i for i, ltr in enumerate(n_x) if ltr == 'N']
#         n_x = list(n_x)
#         for N_index in N_indices:
#             n_x[N_index] = y[N_index]
#         n_x = ''.join(n_x)
# 
#     aligned_x[0] = n_x
#     return tuple(aligned_x)


# Path: mirtop/bam/filter.py
from collections import defaultdict
from mirtop.mirna.realign import hits, cigar_correction, make_cigar, align
import mirtop.libs.logger as mylog

                    add_position.pop()
                if prob == 0:
                    add = []
                    add_position = []
                break

    for e in error:
        if e not in add_position:
            subs.append([e, seq[e], mature[e]])
    if not error:
        add = []
    
    logger.debug("TUNE:: %s %s" % (subs, add))
    
    return subs, "".join(add), make_cigar(seq, mature)


def clean_hits(reads):
    """
    Select only best matches from a list of hits from the same read.

    Args:
        *reads*: dictionary as:

        >>> {'read_id': mirtop.realign.hits, ...}

    Returns:

        *reads*: same than input but with best hits only.
    """

    new_reads = defaultdict(hits)