# Path: crumbs/iterutils.py
# def generate_windows(size, step=None, start=0, end=None):
#     if step is None:
#         step = size
# 
#     win_start = None
#     while True:
#         if win_start is None:
#             win_start = start
#         else:
#             win_start += step
#         win_end = win_start + size
#         if end:
#             if win_end > end:
#                 break
#         yield Window(win_start, win_end)
# 
# Path: crumbs/seq/seqio.py
# def read_seqs(fhands, out_format=None, prefered_seq_classes=None):
#     'It returns a stream of seqs in different codings: seqrecords, seqitems...'
# 
#     if not prefered_seq_classes:
#         prefered_seq_classes = [SEQITEM, SEQRECORD]
#     try:
#         in_format = get_format(fhands[0])
#     except FileIsEmptyError:
#         return []
#     # seqitems is incompatible with different input and output formats
#     # or when in_format != a fasta or fastq
#     if ((out_format not in (None, GUESS_FORMAT) and in_format != out_format
#          and SEQITEM in prefered_seq_classes) or
#         (in_format not in ('fasta',) + SANGER_FASTQ_FORMATS +
#          ILLUMINA_FASTQ_FORMATS)):
#         prefered_seq_classes.pop(prefered_seq_classes.index(SEQITEM))
# 
#     if not prefered_seq_classes:
#         msg = 'No valid seq class left or prefered'
#         raise ValueError(msg)
# 
#     for seq_class in prefered_seq_classes:
#         if seq_class == SEQITEM:
#             try:
#                 return _read_seqitems(fhands)
#             except NotImplementedError:
#                 continue
#         elif seq_class == SEQRECORD:
#             try:
#                 seqs = _read_seqrecords(fhands)
#                 return assing_kind_to_seqs(SEQRECORD, seqs, None)
#             except NotImplementedError:
#                 continue
#         else:
#             raise ValueError('Unknown class for seq: ' + seq_class)
#     raise RuntimeError('We should not be here, fixme')
# 
# Path: crumbs/seq/seq.py
# def get_name(seq):
#     if 'SeqRecord' in seq.__class__.__name__:
#         seq_class = SEQRECORD
#     else:
#         seq_class = seq.kind
#         seq = seq.object
#     if seq_class == SEQITEM:
#         name = seq.name
#     elif seq_class == SEQRECORD:
#         name = seq.id
#     return name
# 
# def get_length(seq):
#     return len(get_str_seq(seq))
# 
# Path: crumbs/utils/file_utils.py
# def flush_fhand(fhand):
#     try:
#         fhand.flush()
#     except IOError, error:
#         # The pipe could be already closed
#         if 'Broken pipe' not in str(error):
#             raise
# 
# Path: crumbs/utils/optional_modules.py
# MSG = 'A python package to run this executable is required,'
# BIO = 'biopython'
# BIO_BGZF = 'biopython with Bgzf support'
#     NCBIXML = create_fake_class(MSG + BIO)
#     NCBIWWW = create_fake_class(MSG + BIO)
# def create_fake_class(msg):
#         def __init__(self, *args, **kwargs):
# def create_fake_funct(msg):
#     def FakeRequiredfunct(*args, **kwargs):
#     class FakePythonRequiredClass(object):


import sys
import gzip
from collections import Counter, OrderedDict, namedtuple
from operator import itemgetter
from io import BytesIO
from crumbs.iterutils import generate_windows
from crumbs.seq.seqio import read_seqs
from crumbs.seq.seq import get_name, get_length
from crumbs.utils.file_utils import flush_fhand
from crumbs.utils.optional_modules import (Reader as pyvcfReader,
                                           Writer as pyvcfWriter,
                                           _Call as pyvcfCall,
                                           _Record as pyvcfRecord,
                                           make_calldata_tuple)
            from traceback import print_exception
    def remove_gt_from_low_qual_calls(self, min_qual):
        'It returns a new SNV with low qual call set to uncalled'
        def call_mapper(call):
            if min_qual is not None and call.gt_qual < min_qual:
                call = call.copy_setting_gt(gt=None, return_pyvcf_call=True)
            else:
                call = call.call
            return call
        return self.copy_mapping_calls(call_mapper)

    def filter_calls_by_sample(self, samples, reverse=False, keep_info=False):
        calls = [self.get_call(sample).call for sample in samples]
        if reverse:
            all_samples = set([c.sample for c in self.calls])
            chosen_samples = set([c.sample for c in calls])
            unchosen_samples = all_samples.difference(chosen_samples)
            calls = [self.get_call(sample).call for sample in unchosen_samples]

        sample_indexes = {call.sample: idx for idx, call in enumerate(calls)}

        alleles = set()
        alleles.update([allele for call in calls if call.called for allele in call.gt_alleles])
        alleles.discard('.')
        int_alleles = list(map(int, alleles))

        record = self.record
        alt_alleles = [a for i, a in enumerate(record.ALT) if i + 1 in int_alleles]
        if not alt_alleles:
            alt_alleles.append(None)
        info = record.INFO if keep_info else {}

# Path: crumbs/iterutils.py
# def generate_windows(size, step=None, start=0, end=None):
#     if step is None:
#         step = size
# 
#     win_start = None
#     while True:
#         if win_start is None:
#             win_start = start
#         else:
#             win_start += step
#         win_end = win_start + size
#         if end:
#             if win_end > end:
#                 break
#         yield Window(win_start, win_end)
# 
# Path: crumbs/seq/seqio.py
# def read_seqs(fhands, out_format=None, prefered_seq_classes=None):
#     'It returns a stream of seqs in different codings: seqrecords, seqitems...'
# 
#     if not prefered_seq_classes:
#         prefered_seq_classes = [SEQITEM, SEQRECORD]
#     try:
#         in_format = get_format(fhands[0])
#     except FileIsEmptyError:
#         return []
#     # seqitems is incompatible with different input and output formats
#     # or when in_format != a fasta or fastq
#     if ((out_format not in (None, GUESS_FORMAT) and in_format != out_format
#          and SEQITEM in prefered_seq_classes) or
#         (in_format not in ('fasta',) + SANGER_FASTQ_FORMATS +
#          ILLUMINA_FASTQ_FORMATS)):
#         prefered_seq_classes.pop(prefered_seq_classes.index(SEQITEM))
# 
#     if not prefered_seq_classes:
#         msg = 'No valid seq class left or prefered'
#         raise ValueError(msg)
# 
#     for seq_class in prefered_seq_classes:
#         if seq_class == SEQITEM:
#             try:
#                 return _read_seqitems(fhands)
#             except NotImplementedError:
#                 continue
#         elif seq_class == SEQRECORD:
#             try:
#                 seqs = _read_seqrecords(fhands)
#                 return assing_kind_to_seqs(SEQRECORD, seqs, None)
#             except NotImplementedError:
#                 continue
#         else:
#             raise ValueError('Unknown class for seq: ' + seq_class)
#     raise RuntimeError('We should not be here, fixme')
# 
# Path: crumbs/seq/seq.py
# def get_name(seq):
#     if 'SeqRecord' in seq.__class__.__name__:
#         seq_class = SEQRECORD
#     else:
#         seq_class = seq.kind
#         seq = seq.object
#     if seq_class == SEQITEM:
#         name = seq.name
#     elif seq_class == SEQRECORD:
#         name = seq.id
#     return name
# 
# def get_length(seq):
#     return len(get_str_seq(seq))
# 
# Path: crumbs/utils/file_utils.py
# def flush_fhand(fhand):
#     try:
#         fhand.flush()
#     except IOError, error:
#         # The pipe could be already closed
#         if 'Broken pipe' not in str(error):
#             raise
# 
# Path: crumbs/utils/optional_modules.py
# MSG = 'A python package to run this executable is required,'
# BIO = 'biopython'
# BIO_BGZF = 'biopython with Bgzf support'
#     NCBIXML = create_fake_class(MSG + BIO)
#     NCBIWWW = create_fake_class(MSG + BIO)
# def create_fake_class(msg):
#         def __init__(self, *args, **kwargs):
# def create_fake_funct(msg):
#     def FakeRequiredfunct(*args, **kwargs):
#     class FakePythonRequiredClass(object):


# Path: crumbs/vcf/snv.py
import sys
import gzip
from collections import Counter, OrderedDict, namedtuple
from operator import itemgetter
from io import BytesIO
from crumbs.iterutils import generate_windows
from crumbs.seq.seqio import read_seqs
from crumbs.seq.seq import get_name, get_length
from crumbs.utils.file_utils import flush_fhand
from crumbs.utils.optional_modules import (Reader as pyvcfReader,
                                           Writer as pyvcfWriter,
                                           _Call as pyvcfCall,
                                           _Record as pyvcfRecord,
                                           make_calldata_tuple)
            from traceback import print_exception

    def remove_gt_from_low_qual_calls(self, min_qual):
        'It returns a new SNV with low qual call set to uncalled'
        def call_mapper(call):
            if min_qual is not None and call.gt_qual < min_qual:
                call = call.copy_setting_gt(gt=None, return_pyvcf_call=True)
            else:
                call = call.call
            return call
        return self.copy_mapping_calls(call_mapper)

    def filter_calls_by_sample(self, samples, reverse=False, keep_info=False):
        calls = [self.get_call(sample).call for sample in samples]
        if reverse:
            all_samples = set([c.sample for c in self.calls])
            chosen_samples = set([c.sample for c in calls])
            unchosen_samples = all_samples.difference(chosen_samples)
            calls = [self.get_call(sample).call for sample in unchosen_samples]

        sample_indexes = {call.sample: idx for idx, call in enumerate(calls)}

        alleles = set()
        alleles.update([allele for call in calls if call.called for allele in call.gt_alleles])
        alleles.discard('.')
        int_alleles = list(map(int, alleles))

        record = self.record
        alt_alleles = [a for i, a in enumerate(record.ALT) if i + 1 in int_alleles]
        if not alt_alleles:
            alt_alleles.append(None)
        info = record.INFO if keep_info else {}

        record = pyvcfRecord(record.CHROM, record.POS, record.ID,