# Path: crumbs/vcf/statistics.py
# def choose_samples(record, sample_names):
#     if sample_names is None:
#         chosen_samples = record.samples
#     else:
#         filter_by_name = lambda x: True if x.sample in sample_names else False
#         chosen_samples = filter(filter_by_name, record.samples,)
#     return chosen_samples
# 
# Path: crumbs/iterutils.py
# class RandomAccessIterator(object):
#     def __init__(self, iterable, rnd_access_win):
#         self._stream = iterable
#         if not rnd_access_win % 2:
#             msg = 'rnd_access_win should be odd'
#             raise ValueError(msg)
#         self._rnd_access_win = rnd_access_win
#         self._buff = []
#         self._curr_item_in_buff = None
#         self._buffer_pos = 0
#         self._stream_consumed = False
#         self._fill_buffer()
# 
#     def _fill_buffer(self):
#         half_win = (self._rnd_access_win - 1) // 2
#         self._buff = list(islice(self._stream, half_win))
#         if len(self._buff) < half_win:
#             self._stream_consumed = True
# 
#     def __iter__(self):
#         return self
# 
#     def next(self):
#         in_buffer = self._buff
#         try:
#             stream_next = self._stream.next()
#         except StopIteration:
#             self._stream_consumed = True
# 
#         if not self._stream_consumed:
#             in_buffer.append(stream_next)
# 
#         if self._curr_item_in_buff is None:
#             self._curr_item_in_buff = 0
#         else:
#             self._curr_item_in_buff += 1
# 
#         try:
#             item_to_yield = in_buffer[self._curr_item_in_buff]
#         except IndexError:
#             raise StopIteration
# 
#         if len(in_buffer) > self._rnd_access_win:
#             in_buffer.pop(0)
#             self._curr_item_in_buff -= 1
#             self._buffer_pos += 1
# 
#         return item_to_yield
# 
#     def _getitem(self, start):
#         start -= self._buffer_pos
#         if start < 0:
#             raise IndexError('Negative indexes not supported')
#         return self._buff[start]
# 
#     def __getitem__(self, index):
#         if isinstance(index, int):
#             start = index
#             return self._getitem(start)
#         else:
#             start = index.start
#             stop = index.stop
#             step = index.step
#         if start is None:
#             start = 0
# 
#         if start < 0 or stop < 0:
#             raise IndexError('Negative indexes not supported')
# 
#         buff_pos = self._buffer_pos
#         start -= buff_pos
#         stop -= buff_pos
# 
#         buff = self._buff
#         if start < 0:
#             raise IndexError('Index outside buffered window')
#         if (not self._stream_consumed and
#            (stop is None or stop > len(buff))):
#             raise IndexError('Index outside buffered window')
# 
#         return buff[start:stop:step]
# 
# 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):


from collections import Counter, namedtuple
from crumbs.vcf.statistics import choose_samples
from crumbs.iterutils import RandomAccessIterator
from crumbs.utils.optional_modules import scipy_fisher
HaploCount = namedtuple('HaploCount', ['AB', 'Ab', 'aB', 'ab'])
Alleles = namedtuple('Alleles', ['A', 'B', 'a', 'b'])
LDStats = namedtuple('LDStats', ['fisher', 'r_sqr'])


def calculate_ld_stats(snp1, snp2, samples=None):
    calls1 = choose_samples(snp1.record, sample_names=samples)
    calls2 = choose_samples(snp2.record, sample_names=samples)
    haplo_counts = _count_biallelic_haplotypes(calls1, calls2)
    fisher = _fisher_exact(haplo_counts)
    rsqr = _calculate_r_sqr(haplo_counts)
    return LDStats(fisher, rsqr)


def _fisher_exact(haplo_counts):
    if not haplo_counts:
        return None
    fish = scipy_fisher(([haplo_counts.AB, haplo_counts.Ab],
                         [haplo_counts.aB, haplo_counts.ab]))[1]
    return fish


def fisher_exact(snp1, snp2, samples=None):
    calls1 = choose_samples(snp1.record, sample_names=samples)
    calls2 = choose_samples(snp2.record, sample_names=samples)
    haplo_counts = _count_biallelic_haplotypes(calls1, calls2)
    return _fisher_exact(haplo_counts)


def calculate_r_sqr(snp1, snp2, samples=None):

# Path: crumbs/vcf/statistics.py
# def choose_samples(record, sample_names):
#     if sample_names is None:
#         chosen_samples = record.samples
#     else:
#         filter_by_name = lambda x: True if x.sample in sample_names else False
#         chosen_samples = filter(filter_by_name, record.samples,)
#     return chosen_samples
# 
# Path: crumbs/iterutils.py
# class RandomAccessIterator(object):
#     def __init__(self, iterable, rnd_access_win):
#         self._stream = iterable
#         if not rnd_access_win % 2:
#             msg = 'rnd_access_win should be odd'
#             raise ValueError(msg)
#         self._rnd_access_win = rnd_access_win
#         self._buff = []
#         self._curr_item_in_buff = None
#         self._buffer_pos = 0
#         self._stream_consumed = False
#         self._fill_buffer()
# 
#     def _fill_buffer(self):
#         half_win = (self._rnd_access_win - 1) // 2
#         self._buff = list(islice(self._stream, half_win))
#         if len(self._buff) < half_win:
#             self._stream_consumed = True
# 
#     def __iter__(self):
#         return self
# 
#     def next(self):
#         in_buffer = self._buff
#         try:
#             stream_next = self._stream.next()
#         except StopIteration:
#             self._stream_consumed = True
# 
#         if not self._stream_consumed:
#             in_buffer.append(stream_next)
# 
#         if self._curr_item_in_buff is None:
#             self._curr_item_in_buff = 0
#         else:
#             self._curr_item_in_buff += 1
# 
#         try:
#             item_to_yield = in_buffer[self._curr_item_in_buff]
#         except IndexError:
#             raise StopIteration
# 
#         if len(in_buffer) > self._rnd_access_win:
#             in_buffer.pop(0)
#             self._curr_item_in_buff -= 1
#             self._buffer_pos += 1
# 
#         return item_to_yield
# 
#     def _getitem(self, start):
#         start -= self._buffer_pos
#         if start < 0:
#             raise IndexError('Negative indexes not supported')
#         return self._buff[start]
# 
#     def __getitem__(self, index):
#         if isinstance(index, int):
#             start = index
#             return self._getitem(start)
#         else:
#             start = index.start
#             stop = index.stop
#             step = index.step
#         if start is None:
#             start = 0
# 
#         if start < 0 or stop < 0:
#             raise IndexError('Negative indexes not supported')
# 
#         buff_pos = self._buffer_pos
#         start -= buff_pos
#         stop -= buff_pos
# 
#         buff = self._buff
#         if start < 0:
#             raise IndexError('Index outside buffered window')
#         if (not self._stream_consumed and
#            (stop is None or stop > len(buff))):
#             raise IndexError('Index outside buffered window')
# 
#         return buff[start:stop:step]
# 
# 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/ld.py
from collections import Counter, namedtuple
from crumbs.vcf.statistics import choose_samples
from crumbs.iterutils import RandomAccessIterator
from crumbs.utils.optional_modules import scipy_fisher

HaploCount = namedtuple('HaploCount', ['AB', 'Ab', 'aB', 'ab'])
Alleles = namedtuple('Alleles', ['A', 'B', 'a', 'b'])
LDStats = namedtuple('LDStats', ['fisher', 'r_sqr'])


def calculate_ld_stats(snp1, snp2, samples=None):
    calls1 = choose_samples(snp1.record, sample_names=samples)
    calls2 = choose_samples(snp2.record, sample_names=samples)
    haplo_counts = _count_biallelic_haplotypes(calls1, calls2)
    fisher = _fisher_exact(haplo_counts)
    rsqr = _calculate_r_sqr(haplo_counts)
    return LDStats(fisher, rsqr)


def _fisher_exact(haplo_counts):
    if not haplo_counts:
        return None
    fish = scipy_fisher(([haplo_counts.AB, haplo_counts.Ab],
                         [haplo_counts.aB, haplo_counts.ab]))[1]
    return fish


def fisher_exact(snp1, snp2, samples=None):
    calls1 = choose_samples(snp1.record, sample_names=samples)
    calls2 = choose_samples(snp2.record, sample_names=samples)
    haplo_counts = _count_biallelic_haplotypes(calls1, calls2)
    return _fisher_exact(haplo_counts)


def calculate_r_sqr(snp1, snp2, samples=None):

    calls1 = choose_samples(snp1.record, sample_names=samples)