# Path: hgvs/exceptions.py
# class HGVSInvalidIntervalError(HGVSError):
#     pass
# 
# Path: hgvs/utils/cigarmapper.py
# class CIGARMapper:
#     """provides coordinate mapping between two sequences whose alignment
#     is given by a CIGAR string
#     
#     CIGAR is about alignments between positions in two sequences.  It
#     is base-centric.
# 
#     Unfortunately, base-centric coordinate systems require additional
#     complexity to refer to zero-width positions.
# 
#     This code uses interbase intervals.  Interbase positions are
#     zero-width boundaries between bases.  They often look similar to
#     zero-based, right open coordinates. (But don't call them that.  It
#     upsets me deeply.)  The most important difference is that zero
#     width intervals neatly represent insertions between bases (or
#     before or after the sequence).
# 
#     """
# 
#     def __init__(self, cigar):
#         self.cigar = cigar
#         self.ref_pos, self.tgt_pos, self.cigar_op = _parse_cigar(self.cigar)
# 
# 
#     def __repr__(self):
#         return f"CIGARMapper(cigar='{self.cigar}')"
# 
# 
#     @property
#     def ref_len(self):
#         return self.ref_pos[-1]
# 
# 
#     @property
#     def tgt_len(self):
#         return self.tgt_pos[-1]
# 
# 
#     def map_ref_to_tgt(self, pos, end, strict_bounds=True):
#         return self._map(from_pos=self.ref_pos, to_pos=self.tgt_pos, pos=pos, end=end, strict_bounds=strict_bounds)
# 
# 
#     def map_tgt_to_ref(self, pos, end, strict_bounds=True):
#         return self._map(from_pos=self.tgt_pos, to_pos=self.ref_pos, pos=pos, end=end, strict_bounds=strict_bounds)
# 
# 
#     def _map(self, from_pos, to_pos, pos, end, strict_bounds):
#         """Map position between aligned segments
# 
#         Positions in this function are 0-based, base-counting. 
#         """
# 
#         if strict_bounds and (pos < 0 or pos > from_pos[-1]):
#             raise HGVSInvalidIntervalError("Position is beyond the bounds of transcript record")
# 
#         # find aligned segment to use as basis for mapping
#         # okay for pos to be before first element or after last
#         for pos_i in range(len(self.cigar_op)):
#             if pos < from_pos[pos_i+1]:
#                 break
# 
#         if self.cigar_op[pos_i] in "=MX":
#             mapped_pos = to_pos[pos_i] + (pos - from_pos[pos_i])
#             mapped_pos_offset = 0
# 
#         elif self.cigar_op[pos_i] in "DI":
#             mapped_pos = to_pos[pos_i]
#             if end == "start":
#                 mapped_pos -= 1
#             mapped_pos_offset = 0
# 
#         elif self.cigar_op[pos_i] == "N":
#             if pos - from_pos[pos_i] + 1 <= from_pos[pos_i + 1] - pos:
#                 mapped_pos = to_pos[pos_i] - 1
#                 mapped_pos_offset = pos - from_pos[pos_i] + 1
#             else:
#                 mapped_pos = to_pos[pos_i]
#                 mapped_pos_offset = -(from_pos[pos_i + 1] - pos)
# 
#         return mapped_pos, mapped_pos_offset, self.cigar_op[pos_i]


import pytest
from hgvs.exceptions import HGVSInvalidIntervalError
from hgvs.utils.cigarmapper import CIGARMapper
    # tgt to ref
    assert cm.map_tgt_to_ref(0,'start') == (0, 0, '=')
    assert cm.map_tgt_to_ref(0,'end') == (0, 0, '=')
    assert cm.map_tgt_to_ref(1,'start') == (1, 0, '=')
    assert cm.map_tgt_to_ref(1,'end') == (1, 0, '=')
    assert cm.map_tgt_to_ref(2,'start') == (2, 0, '=')
    assert cm.map_tgt_to_ref(2,'end') == (2, 0, '=')
    assert cm.map_tgt_to_ref(3,'start') == (5, 0, '=')
    assert cm.map_tgt_to_ref(3,'end') == (5, 0, '=')
    assert cm.map_tgt_to_ref(4,'start') == (6, 0, 'X')
    assert cm.map_tgt_to_ref(4,'end') == (6, 0, 'X')
    assert cm.map_tgt_to_ref(5,'start') == (7, 0, '=')
    assert cm.map_tgt_to_ref(5,'end') == (7, 0, '=')
    assert cm.map_tgt_to_ref(6,'start') == (11, 0, '=')
    assert cm.map_tgt_to_ref(6,'end') == (11, 0, '=')
    assert cm.map_tgt_to_ref(7,'start') == (13, 0, '=')
    assert cm.map_tgt_to_ref(7,'end') == (13, 0, '=')
    assert cm.map_tgt_to_ref(8,'start') == (13, 0, 'D')
    assert cm.map_tgt_to_ref(8,'end') == (14, 0, 'D')
    assert cm.map_tgt_to_ref(9,'start') == (14, 0, '=')
    assert cm.map_tgt_to_ref(9,'end') == (14, 0, '=')


    
def test_cigarmapper_strict_bounds():
    # exception raised for out of bounds on left?
    with pytest.raises(HGVSInvalidIntervalError):
        cm.map_ref_to_tgt(-1, "start", strict_bounds=True)

    # ... and right?

# Path: hgvs/exceptions.py
# class HGVSInvalidIntervalError(HGVSError):
#     pass
# 
# Path: hgvs/utils/cigarmapper.py
# class CIGARMapper:
#     """provides coordinate mapping between two sequences whose alignment
#     is given by a CIGAR string
#     
#     CIGAR is about alignments between positions in two sequences.  It
#     is base-centric.
# 
#     Unfortunately, base-centric coordinate systems require additional
#     complexity to refer to zero-width positions.
# 
#     This code uses interbase intervals.  Interbase positions are
#     zero-width boundaries between bases.  They often look similar to
#     zero-based, right open coordinates. (But don't call them that.  It
#     upsets me deeply.)  The most important difference is that zero
#     width intervals neatly represent insertions between bases (or
#     before or after the sequence).
# 
#     """
# 
#     def __init__(self, cigar):
#         self.cigar = cigar
#         self.ref_pos, self.tgt_pos, self.cigar_op = _parse_cigar(self.cigar)
# 
# 
#     def __repr__(self):
#         return f"CIGARMapper(cigar='{self.cigar}')"
# 
# 
#     @property
#     def ref_len(self):
#         return self.ref_pos[-1]
# 
# 
#     @property
#     def tgt_len(self):
#         return self.tgt_pos[-1]
# 
# 
#     def map_ref_to_tgt(self, pos, end, strict_bounds=True):
#         return self._map(from_pos=self.ref_pos, to_pos=self.tgt_pos, pos=pos, end=end, strict_bounds=strict_bounds)
# 
# 
#     def map_tgt_to_ref(self, pos, end, strict_bounds=True):
#         return self._map(from_pos=self.tgt_pos, to_pos=self.ref_pos, pos=pos, end=end, strict_bounds=strict_bounds)
# 
# 
#     def _map(self, from_pos, to_pos, pos, end, strict_bounds):
#         """Map position between aligned segments
# 
#         Positions in this function are 0-based, base-counting. 
#         """
# 
#         if strict_bounds and (pos < 0 or pos > from_pos[-1]):
#             raise HGVSInvalidIntervalError("Position is beyond the bounds of transcript record")
# 
#         # find aligned segment to use as basis for mapping
#         # okay for pos to be before first element or after last
#         for pos_i in range(len(self.cigar_op)):
#             if pos < from_pos[pos_i+1]:
#                 break
# 
#         if self.cigar_op[pos_i] in "=MX":
#             mapped_pos = to_pos[pos_i] + (pos - from_pos[pos_i])
#             mapped_pos_offset = 0
# 
#         elif self.cigar_op[pos_i] in "DI":
#             mapped_pos = to_pos[pos_i]
#             if end == "start":
#                 mapped_pos -= 1
#             mapped_pos_offset = 0
# 
#         elif self.cigar_op[pos_i] == "N":
#             if pos - from_pos[pos_i] + 1 <= from_pos[pos_i + 1] - pos:
#                 mapped_pos = to_pos[pos_i] - 1
#                 mapped_pos_offset = pos - from_pos[pos_i] + 1
#             else:
#                 mapped_pos = to_pos[pos_i]
#                 mapped_pos_offset = -(from_pos[pos_i + 1] - pos)
# 
#         return mapped_pos, mapped_pos_offset, self.cigar_op[pos_i]


# Path: tests/test_hgvs_utils_cigarmapper.py
import pytest
from hgvs.exceptions import HGVSInvalidIntervalError
from hgvs.utils.cigarmapper import CIGARMapper

    # tgt to ref
    assert cm.map_tgt_to_ref(0,'start') == (0, 0, '=')
    assert cm.map_tgt_to_ref(0,'end') == (0, 0, '=')
    assert cm.map_tgt_to_ref(1,'start') == (1, 0, '=')
    assert cm.map_tgt_to_ref(1,'end') == (1, 0, '=')
    assert cm.map_tgt_to_ref(2,'start') == (2, 0, '=')
    assert cm.map_tgt_to_ref(2,'end') == (2, 0, '=')
    assert cm.map_tgt_to_ref(3,'start') == (5, 0, '=')
    assert cm.map_tgt_to_ref(3,'end') == (5, 0, '=')
    assert cm.map_tgt_to_ref(4,'start') == (6, 0, 'X')
    assert cm.map_tgt_to_ref(4,'end') == (6, 0, 'X')
    assert cm.map_tgt_to_ref(5,'start') == (7, 0, '=')
    assert cm.map_tgt_to_ref(5,'end') == (7, 0, '=')
    assert cm.map_tgt_to_ref(6,'start') == (11, 0, '=')
    assert cm.map_tgt_to_ref(6,'end') == (11, 0, '=')
    assert cm.map_tgt_to_ref(7,'start') == (13, 0, '=')
    assert cm.map_tgt_to_ref(7,'end') == (13, 0, '=')
    assert cm.map_tgt_to_ref(8,'start') == (13, 0, 'D')
    assert cm.map_tgt_to_ref(8,'end') == (14, 0, 'D')
    assert cm.map_tgt_to_ref(9,'start') == (14, 0, '=')
    assert cm.map_tgt_to_ref(9,'end') == (14, 0, '=')


    
def test_cigarmapper_strict_bounds():
    # exception raised for out of bounds on left?
    with pytest.raises(HGVSInvalidIntervalError):
        cm.map_ref_to_tgt(-1, "start", strict_bounds=True)

    # ... and right?

    with pytest.raises(HGVSInvalidIntervalError):