# Path: denovoFilter/change_last_base_sites.py
# def change_conserved_last_base_consequence(de_novos, last_base_path):
#     """ reannotate the consequence of conserved sites at the end of exons
#     
#     Args:
#         de_novos: pandas dataframe of candidate de novos
#         last_base_path: path to file listing conserved sites at the end of exons
#     
#     Returns:
#         dataframe, but with the conserved sites consequence reannotated as
#         "conserved_exon_terminus_variant"
#     """
#     
#     with open(last_base_path, "r") as handle:
#         sites_json = json.load(handle)
#     
#     # get a dictionary of sites per chromosome
#     sites = {}
#     for (chrom, pos) in sites_json:
#         if chrom not in sites:
#             sites[chrom] = set([])
#         
#         sites[chrom].add(int(pos))
#     
#     # find the sites for each chromosome at conserved last base of exons, and
#     # give them a new consequence value.
#     for chrom in sites:
#         positions = sites[chrom]
#         
#         # find which sites are for the correct chromosome, at one of the
#         # identified sites, and have a single base alleles (i.e "C" or "G")
#         in_chrom = de_novos["chrom"] == chrom
#         in_pos = de_novos["pos"].isin(positions)
#         single_base = (de_novos["ref"].str.len() == 1) & (de_novos["alt"].str.len() == 1)
#         
#         cq = de_novos["consequence"].copy()
#         cq[in_chrom & in_pos & single_base] = "conserved_exon_terminus_variant"
#         de_novos["consequence"] = cq
#     
#     return de_novos
# 
# Path: tests/compare_dataframes.py
# class CompareTables(unittest.TestCase):
#     def compare_tables(self, first, second):
#         """ check if two Dataframes contain the same information.
#         
#         Note that the dataframes don't have to have the same column order.
#         
#         Args:
#             first: pandas DataFrame
#             second: pandas DataFrame
#         """
#         
#         # make sure the two tables have the same columns, and number of rows
#         self.assertEqual(set(first.columns), set(second.columns))
#         self.assertEqual(len(first), len(second))
#         
#         # make sure the values in the columns are identical between tables.
#         # We have to run through all the values one by one, to make sure that
#         # NaN values compare correctly.
#         for column in first:
#             for pos in range(len(first)):
#                 first_val = first[column][pos]
#                 second_val = second[column][pos]
#                 
#                 # prepare a suitable diagnostic error message if the values are
#                 #  not equal
#                 if type(first_val) == str or first_val is None or type(first_val) == numpy.bool_:
#                     msg = "{} != {} at position {} in {}".format(first_val,
#                         second_val, pos, column)
#                 else:
#                     msg = "{:.20f} != {:.20f} at position {} in {}".format( \
#                         first_val, second_val, pos, column)
#                 
#                 if type(first_val) in [float, numpy.float64] and math.isnan(first_val):
#                     # if one is nan, check that the other is also nan, since
#                     # nan entries cannot be chacked for eqaulity.
#                     self.assertTrue(math.isnan(second_val), msg)
#                 elif type(first_val) in [float, numpy.float64]:
#                     # Only check if floats are nearly equal to get around float
#                     # precision issues.
#                     self.assertAlmostEqual(first_val, second_val, msg=msg)
#                 else:
#                     self.assertEqual(first_val, second_val, msg)


import unittest
import tempfile
import json
from pandas import DataFrame
from denovoFilter.change_last_base_sites import change_conserved_last_base_consequence
from tests.compare_dataframes import CompareTables




class TestChangeLastBaseSites(CompareTables):
    
    def test_change_last_base_sites(self):
        ''' check conversion of consequences for sites at the last bae of exons
        '''
        
        temp = tempfile.NamedTemporaryFile(mode='w')
        json.dump([['1', 10], ['2', 10]], temp)
        temp.flush()
        
        # define a table of variants. The first is a variant where the
        # consequence needs to be changed, the second isn't at an appropriate
        # location, and the third, although at an appropriate location, isn't
        # for a SNV, so does not need to be changed
        variants = DataFrame({'person_stable_id': ['a', 'b', 'c'],
            'chrom': ['1', '2', '2'],
            'pos': [10, 1, 10],
            'ref': ['A', 'G', 'GG'],
            'alt': ['C', 'T', 'G'],
            'consequence': ['synonymous_variant', 'synonymous_variant', 'frameshift_variant'],
            })
        
        # define an expected output, aside from a modified consequence
        expected = variants.copy()
        expected['consequence'] = ['conserved_exon_terminus_variant', 'synonymous_variant', 'frameshift_variant']
        

# Path: denovoFilter/change_last_base_sites.py
# def change_conserved_last_base_consequence(de_novos, last_base_path):
#     """ reannotate the consequence of conserved sites at the end of exons
#     
#     Args:
#         de_novos: pandas dataframe of candidate de novos
#         last_base_path: path to file listing conserved sites at the end of exons
#     
#     Returns:
#         dataframe, but with the conserved sites consequence reannotated as
#         "conserved_exon_terminus_variant"
#     """
#     
#     with open(last_base_path, "r") as handle:
#         sites_json = json.load(handle)
#     
#     # get a dictionary of sites per chromosome
#     sites = {}
#     for (chrom, pos) in sites_json:
#         if chrom not in sites:
#             sites[chrom] = set([])
#         
#         sites[chrom].add(int(pos))
#     
#     # find the sites for each chromosome at conserved last base of exons, and
#     # give them a new consequence value.
#     for chrom in sites:
#         positions = sites[chrom]
#         
#         # find which sites are for the correct chromosome, at one of the
#         # identified sites, and have a single base alleles (i.e "C" or "G")
#         in_chrom = de_novos["chrom"] == chrom
#         in_pos = de_novos["pos"].isin(positions)
#         single_base = (de_novos["ref"].str.len() == 1) & (de_novos["alt"].str.len() == 1)
#         
#         cq = de_novos["consequence"].copy()
#         cq[in_chrom & in_pos & single_base] = "conserved_exon_terminus_variant"
#         de_novos["consequence"] = cq
#     
#     return de_novos
# 
# Path: tests/compare_dataframes.py
# class CompareTables(unittest.TestCase):
#     def compare_tables(self, first, second):
#         """ check if two Dataframes contain the same information.
#         
#         Note that the dataframes don't have to have the same column order.
#         
#         Args:
#             first: pandas DataFrame
#             second: pandas DataFrame
#         """
#         
#         # make sure the two tables have the same columns, and number of rows
#         self.assertEqual(set(first.columns), set(second.columns))
#         self.assertEqual(len(first), len(second))
#         
#         # make sure the values in the columns are identical between tables.
#         # We have to run through all the values one by one, to make sure that
#         # NaN values compare correctly.
#         for column in first:
#             for pos in range(len(first)):
#                 first_val = first[column][pos]
#                 second_val = second[column][pos]
#                 
#                 # prepare a suitable diagnostic error message if the values are
#                 #  not equal
#                 if type(first_val) == str or first_val is None or type(first_val) == numpy.bool_:
#                     msg = "{} != {} at position {} in {}".format(first_val,
#                         second_val, pos, column)
#                 else:
#                     msg = "{:.20f} != {:.20f} at position {} in {}".format( \
#                         first_val, second_val, pos, column)
#                 
#                 if type(first_val) in [float, numpy.float64] and math.isnan(first_val):
#                     # if one is nan, check that the other is also nan, since
#                     # nan entries cannot be chacked for eqaulity.
#                     self.assertTrue(math.isnan(second_val), msg)
#                 elif type(first_val) in [float, numpy.float64]:
#                     # Only check if floats are nearly equal to get around float
#                     # precision issues.
#                     self.assertAlmostEqual(first_val, second_val, msg=msg)
#                 else:
#                     self.assertEqual(first_val, second_val, msg)


# Path: tests/test_change_last_base_sites.py
import unittest
import tempfile
import json
from pandas import DataFrame
from denovoFilter.change_last_base_sites import change_conserved_last_base_consequence
from tests.compare_dataframes import CompareTables





class TestChangeLastBaseSites(CompareTables):
    
    def test_change_last_base_sites(self):
        ''' check conversion of consequences for sites at the last bae of exons
        '''
        
        temp = tempfile.NamedTemporaryFile(mode='w')
        json.dump([['1', 10], ['2', 10]], temp)
        temp.flush()
        
        # define a table of variants. The first is a variant where the
        # consequence needs to be changed, the second isn't at an appropriate
        # location, and the third, although at an appropriate location, isn't
        # for a SNV, so does not need to be changed
        variants = DataFrame({'person_stable_id': ['a', 'b', 'c'],
            'chrom': ['1', '2', '2'],
            'pos': [10, 1, 10],
            'ref': ['A', 'G', 'GG'],
            'alt': ['C', 'T', 'G'],
            'consequence': ['synonymous_variant', 'synonymous_variant', 'frameshift_variant'],
            })
        
        # define an expected output, aside from a modified consequence
        expected = variants.copy()
        expected['consequence'] = ['conserved_exon_terminus_variant', 'synonymous_variant', 'frameshift_variant']
        

        self.compare_tables(change_conserved_last_base_consequence(variants, temp.name), expected)