# Path: scripts/seq_classes.py
# class allele(object):
#     """
#     The allele present at a loci and their accompanying data
#     """
#     def __init__(self,nucleotide):
#         self.nucleotide=nucleotide
#         self.count = 0
#         self.freq = 0
#         self.mutationalClass =[] 
#     def classifyVar(self,sequence,codingRegion,pos):
#         self.mutationalClass.append(classify(sequence,codingRegion,pos,self.nucleotide))
#     def reprJSON(self): # https://stackoverflow.com/questions/5160077/encoding-nested-python-object-in-json
#         d = dict()
#         for a, v in self.__dict__.items():
#             if (hasattr(v, "reprJSON")):
#                 d[a] = v.reprJSON()
#             else:
#                 d[a] = v
#         return d
# 
# def checkORF(seq):
#     """
#     This function varifies the input is an ORF by checking it has
#     i) a start codon
#     ii) is made of complete codons mod(lenth(seg),3)=0 taking gaps into account
#     iii) Has a stop codon at the end and not before.
#     """
#     protien = seq.translate()
#    # check for ATG at start
#     if seq.find('ATG') !=0:
#         if seq.find('ATG') ==-1:
#             raise ValueError("No start codon")
#         if seq.find('ATG')>0:
#             raise ValueError("start codon found at position "+ str(seq.find('ATG')))
#     
#     elif len(seq)% 3!=0:
#         raise ValueError("The sequence is not multiple of 3") 
#        
#     elif protien.find('*')  != len(protien)-1:
#         if protien.find('*') ==-1:
#             raise ValueError("No stop codon in ORF")
#         else:
#             raise ValueError("Internal stop codon found at position "+ str(protien.find('*')))
#     
#     else:
#         return(True)
# 
# def classify(sequence,codingRegion,pos,nucleotide):
#        
#         """
#         seqeunce is a seqRecord
#         codingRegion is a diction in the form 
#         {
#             "name": "NS1",
#             "regions": [
#                 {
#                     "start": 26,
#                     "stop": 719
#                 }
#             ]
#         }
#         The ouput is a dictionary added to the mutationalClass list
#         it is of the form 
#         {
#             ORF: The name of the ORF,
#             codonPos: the position in the codon either [0,1,2],
#             codingPos: the nucleotide position in the ORF
#             aminoAcidPos: The position of the amino acid in the polypetide,
#             consensusAA: The consensus amino acid,
#             varAA: The variant amino acid,
#             classification: Nonsynonymous,Synonymous,indel, stop,
#         }
#         """
#         # Get the coding sequence
#         # Get the new position in the coding sequence
#         i = 0
#         # Has to catch the case where it's outside these regions
#         outsideORF=True
#         for seg in codingRegion["regions"]:
#             if pos >= seg["start"] and pos<seg["stop"]:
#                 outsideORF=False
#                 break
#             else:
#                 i+=1
#         if outsideORF:
#             return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": None,
#                 "codingPos": None,
#                 "aminoAcidPos": None,
#                 "consensusAA": None,
#                 "varAA": None,
#                 "classification": "Noncoding"
# 
#             })
#         
#         codingSequence=""
#         for seg in codingRegion["regions"]:
#             codingSequence=codingSequence+sequence[seg["start"]:seg["stop"]]
#         #consensusSequence = Seq(codingSequence,generic_dna)
#         checkORF(codingSequence)
#         
#         posInSeg = pos-codingRegion["regions"][i]["start"]
#         otherRegions = codingRegion["regions"][:i]
#         adjustment = 0
#         if len(otherRegions)>0:
#             for seg in otherRegions:
#                 adjustment+=seg["stop"]-seg["start"]
#         
#         codingPos = posInSeg+adjustment
#         codonPos = codingPos % 3
#         aminoAcidPos = codingPos // 3 
# 
#         consensusProtien = codingSequence.translate()
#         consensusAA = consensusProtien[aminoAcidPos]
# 
#         if nucleotide=="-":
#             return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": codonPos,
#                 "codingPos": codingPos,
#                 "aminoAcidPos": aminoAcidPos,
#                 "consensusAA": consensusAA,
#                 "varAA": None,
#                 "classification": "Indel"
#             })
# 
#         mutantCodingSequence = codingSequence        
#         mutantCodingSequence = mutantCodingSequence[:codingPos]+ str(nucleotide) + mutantCodingSequence[codingPos+1:] # this is still seq object
#         #mutantSequence = Seq(mutantCodingSequence,generic_dna)
#         mutantProtein = mutantCodingSequence.translate()
# 
#         varAA = mutantProtein[aminoAcidPos]
# 
#         if varAA==consensusAA:
#             classification = "Synonymous"
#         elif varAA=="*":
#             classification = "Stop"
#         elif consensusAA=="*" and varAA!=consensusAA:
#             classification= "Readthrough"
#         elif varAA!=consensusAA:
#             classification="Nonsynonymous"
# 
#         return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": codonPos,
#                 "codingPos": codingPos,
#                 "aminoAcidPos": aminoAcidPos,
#                 "consensusAA": consensusAA,
#                 "varAA": varAA,
#                 "classification": classification
#                  })


import unittest
import pysam
from Bio.Seq import Seq
from Bio import SeqIO
from Bio.Alphabet import generic_dna
from Bio.SeqRecord import SeqRecord
from scripts.seq_classes import allele, checkORF,classify

class test_checkORF(unittest.TestCase):
        
    def tearDown(self):
        """
        This method is called after each test
        """
        pass

    def test_good(self):
        sequence = Seq("ATGATGTAA")

# Path: scripts/seq_classes.py
# class allele(object):
#     """
#     The allele present at a loci and their accompanying data
#     """
#     def __init__(self,nucleotide):
#         self.nucleotide=nucleotide
#         self.count = 0
#         self.freq = 0
#         self.mutationalClass =[] 
#     def classifyVar(self,sequence,codingRegion,pos):
#         self.mutationalClass.append(classify(sequence,codingRegion,pos,self.nucleotide))
#     def reprJSON(self): # https://stackoverflow.com/questions/5160077/encoding-nested-python-object-in-json
#         d = dict()
#         for a, v in self.__dict__.items():
#             if (hasattr(v, "reprJSON")):
#                 d[a] = v.reprJSON()
#             else:
#                 d[a] = v
#         return d
# 
# def checkORF(seq):
#     """
#     This function varifies the input is an ORF by checking it has
#     i) a start codon
#     ii) is made of complete codons mod(lenth(seg),3)=0 taking gaps into account
#     iii) Has a stop codon at the end and not before.
#     """
#     protien = seq.translate()
#    # check for ATG at start
#     if seq.find('ATG') !=0:
#         if seq.find('ATG') ==-1:
#             raise ValueError("No start codon")
#         if seq.find('ATG')>0:
#             raise ValueError("start codon found at position "+ str(seq.find('ATG')))
#     
#     elif len(seq)% 3!=0:
#         raise ValueError("The sequence is not multiple of 3") 
#        
#     elif protien.find('*')  != len(protien)-1:
#         if protien.find('*') ==-1:
#             raise ValueError("No stop codon in ORF")
#         else:
#             raise ValueError("Internal stop codon found at position "+ str(protien.find('*')))
#     
#     else:
#         return(True)
# 
# def classify(sequence,codingRegion,pos,nucleotide):
#        
#         """
#         seqeunce is a seqRecord
#         codingRegion is a diction in the form 
#         {
#             "name": "NS1",
#             "regions": [
#                 {
#                     "start": 26,
#                     "stop": 719
#                 }
#             ]
#         }
#         The ouput is a dictionary added to the mutationalClass list
#         it is of the form 
#         {
#             ORF: The name of the ORF,
#             codonPos: the position in the codon either [0,1,2],
#             codingPos: the nucleotide position in the ORF
#             aminoAcidPos: The position of the amino acid in the polypetide,
#             consensusAA: The consensus amino acid,
#             varAA: The variant amino acid,
#             classification: Nonsynonymous,Synonymous,indel, stop,
#         }
#         """
#         # Get the coding sequence
#         # Get the new position in the coding sequence
#         i = 0
#         # Has to catch the case where it's outside these regions
#         outsideORF=True
#         for seg in codingRegion["regions"]:
#             if pos >= seg["start"] and pos<seg["stop"]:
#                 outsideORF=False
#                 break
#             else:
#                 i+=1
#         if outsideORF:
#             return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": None,
#                 "codingPos": None,
#                 "aminoAcidPos": None,
#                 "consensusAA": None,
#                 "varAA": None,
#                 "classification": "Noncoding"
# 
#             })
#         
#         codingSequence=""
#         for seg in codingRegion["regions"]:
#             codingSequence=codingSequence+sequence[seg["start"]:seg["stop"]]
#         #consensusSequence = Seq(codingSequence,generic_dna)
#         checkORF(codingSequence)
#         
#         posInSeg = pos-codingRegion["regions"][i]["start"]
#         otherRegions = codingRegion["regions"][:i]
#         adjustment = 0
#         if len(otherRegions)>0:
#             for seg in otherRegions:
#                 adjustment+=seg["stop"]-seg["start"]
#         
#         codingPos = posInSeg+adjustment
#         codonPos = codingPos % 3
#         aminoAcidPos = codingPos // 3 
# 
#         consensusProtien = codingSequence.translate()
#         consensusAA = consensusProtien[aminoAcidPos]
# 
#         if nucleotide=="-":
#             return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": codonPos,
#                 "codingPos": codingPos,
#                 "aminoAcidPos": aminoAcidPos,
#                 "consensusAA": consensusAA,
#                 "varAA": None,
#                 "classification": "Indel"
#             })
# 
#         mutantCodingSequence = codingSequence        
#         mutantCodingSequence = mutantCodingSequence[:codingPos]+ str(nucleotide) + mutantCodingSequence[codingPos+1:] # this is still seq object
#         #mutantSequence = Seq(mutantCodingSequence,generic_dna)
#         mutantProtein = mutantCodingSequence.translate()
# 
#         varAA = mutantProtein[aminoAcidPos]
# 
#         if varAA==consensusAA:
#             classification = "Synonymous"
#         elif varAA=="*":
#             classification = "Stop"
#         elif consensusAA=="*" and varAA!=consensusAA:
#             classification= "Readthrough"
#         elif varAA!=consensusAA:
#             classification="Nonsynonymous"
# 
#         return({
#                 "ORF": codingRegion["name"],
#                 "codonPos": codonPos,
#                 "codingPos": codingPos,
#                 "aminoAcidPos": aminoAcidPos,
#                 "consensusAA": consensusAA,
#                 "varAA": varAA,
#                 "classification": classification
#                  })


# Path: test/mutational_class_test.py
import unittest
import pysam
from Bio.Seq import Seq
from Bio import SeqIO
from Bio.Alphabet import generic_dna
from Bio.SeqRecord import SeqRecord
from scripts.seq_classes import allele, checkORF,classify


class test_checkORF(unittest.TestCase):
        
    def tearDown(self):
        """
        This method is called after each test
        """
        pass

    def test_good(self):
        sequence = Seq("ATGATGTAA")

        self.assertTrue(checkORF(sequence))