
# Copyright (c) 2020, Build-A-Cell. All rights reserved.
# See LICENSE file in the project root directory for details.

import copy
from warnings import warn

from .dna_part import DNA_part
from .mechanisms_binding import One_Step_Cooperative_Binding
from .species import Species

integrase_sites = ["attB","attP","attL","attR","FLP","CRE"]
class DNABindingSite(DNA_part):
    def __init__(self,name,binders,no_stop_codons=None,assembly = None,**keywords):
        """an integrase attachment site binds to integrase"""

        if(isinstance(binders,list)):
            self.binders = [self.set_species(a) for a in binders]
        else:
            self.binders = [binders]
        self.mechanisms = {"binding":One_Step_Cooperative_Binding()}
        DNA_part.__init__(self,name,no_stop_codons=no_stop_codons,mechanisms = self.mechanisms,assembly = assembly,**keywords)
        self.name = name
        #self.assembly = None
        
    def __repr__(self):
        myname = self.name
        return myname
    def update_species(self):
        spec = []
        spec += self.binders
        if(self.dna_to_bind is not None):
            mech_b = self.mechanisms["binding"]
            for binder in self.binders:
                spec += mech_b.update_species(binder,self.dna_to_bind,component=self,part_id = self.name)
                #TODO: different proteins probably have different affinity to bind this sequence
        return spec
    def update_reactions(self):
        rxns = []
        if(self.dna_to_bind is not None):
            mech_b = self.mechanisms["binding"]
            for binder in self.binders:
                rxns += mech_b.update_reactions(binder,self.dna_to_bind,component=self,part_id = self.name)
        return rxns
    def update_component(self,dna,rnas=None,proteins=None,mypos = None):
        """returns a copy of this component, except with the proper fields updated"""
        out_component = copy.deepcopy(self)
        if(mypos is not None):
            out_component.dna_to_bind = dna[mypos]
        else:
            out_component.dna_to_bind = dna
        if(dna.material_type == "rna"):
            #DNA binding sites only work with DNA
            return None
        elif(dna.material_type == "dna"):
            return out_component
class AttachmentSite(DNABindingSite):
    #TODO generalize to "DNA binding site"
    def __init__(self,name, site_type = "attB",integrase = "int1", dinucleotide = 1,no_stop_codons=None,**keywords):
        if(isinstance(integrase,Species)):
            self.integrase_species = integrase
            self.integrase = integrase.name
        elif(isinstance(integrase,str)):
            self.integrase_species = Species(integrase,material_type="protein")
            self.integrase = integrase
        #self.integrase = integrase
        self.dinucleotide = dinucleotide
        self.site_type = site_type
        DNABindingSite.__init__(self,name,self.integrase_species,no_stop_codons=no_stop_codons,**keywords)
    def __repr__(self):
        myname = self.name
        if(self.site_type in integrase_sites):
            myname += "_" + self.integrase
            if(self.dinucleotide != 1):
                myname += "_"+str(self.dinucleotide) 
        else:
            warn("warning! site {} has site_type {} which is not recognized".format(self.name,self.site_type))
        return myname
