# vim: set fileencoding=utf-8 :
#
# Copyright (C) 2010-2012 Marnix H. Medema
# University of Groningen
# Department of Microbial Physiology / Groningen Bioinformatics Centre
#
# Copyright (C) 2011-2013 Kai Blin
# University of Tuebingen
# Interfaculty Institute of Microbiology and Infection Medicine
# Div. of Microbiology/Biotechnology
#
# License: GNU Affero General Public License v3 or later
# A copy of GNU AGPL v3 should have been included in this software package in LICENSE.txt.

from pyquery import PyQuery as pq
from antismash import utils

def will_handle(product):
    if product.find('thiopeptide') > -1:
        return True

    return False

def generate_details_div(cluster, seq_record, options, js_domains, details=None):
    """Generate details div"""

    cluster_rec = utils.get_cluster_by_nr(seq_record, cluster['idx'])
    if cluster_rec is None:
        return details

    leader_peptides = _find_leader_peptides(cluster_rec, seq_record)
    core_peptides = _find_core_peptides(cluster_rec, seq_record)

    if details is None:
        details = pq('<div>')
        details.addClass('details')

        header = pq('<h3>')
        header.text('Detailed annotation')
        details.append(header)

    if len(core_peptides) == 0:
        details_text = pq('<div>')
        details_text.addClass('details-text')
        details_text.text('No core peptides found.')
        details.append(details_text)
        return details

    details_text = pq('<dl>')
    details_text.addClass('details-text')
    hrtag=pq('<hr>')
    header2 = pq('<h4>')
    header2.text('Thiopeptide(s)')
    details.append(header2)
    details.append(hrtag)

    
    i = 0
    for cp in core_peptides:
        leader = leader_peptides[i]
        leader_seq = _get_leader_peptide_sequence(leader)
        core_seq = _get_core_peptide_sequence(cp)
        thio_c_cut = _get_tail_cut(cp)
        dt = pq('<dt>')
        dt.text('%s leader / core peptide, putative %s' % (utils.get_gene_id(cp), _get_core_peptide_type(cp)))
        details_text.append(dt)

        dd = pq('<dd>')
        core_seq = core_seq.replace('S', '<span class="dha">Dha</span>')
        tail_seq ='<span class="cut">'+thio_c_cut+'</span>'
        core_seq = core_seq.replace('T', '<span class="dhb">Dhb</span>')
        core_seq = core_seq.replace('C', '<span class="cys">C</span>')
        core_seq = core_seq + tail_seq
        seq = "%s - %s" % (leader_seq, core_seq)
        dd.html(seq)
        details_text.append(dd)
        i += 1

    details.append(details_text)

    legend = pq('<div>')
    legend.addClass('legend')
    legend_header = pq('<h4>')
    legend_header.text('Legend:')
    legend.append(legend_header)

    legend_text = pq('<div>')
    legend_text.html('<span class="dha">Dha</span>: Didehydroalanine<br>'
                     '<span class="dhb">Dhb</span>: Didehydrobutyrine<br>'
                     '<span class="cut">Grey</span>: Putative cleaved off residues<br>'
                     '<span>Type I</span>: Featuring genes encoding indolic acid side ring (series e)<br>'
    '<span>Type II</span>: Featuring the gene coding for quinaldic acid moiety formation  (series a&b, c)<br>'
                     '<span>Type III</span>: No genes for synthesizing L-trp derivatives (series d)<br>')
    legend.append(legend_text)
    details.append(legend)

    return details

def generate_sidepanel(cluster, seq_record, options, sidepanel=None):
    """Generate sidepanel div"""
    
    cluster_rec = utils.get_cluster_by_nr(seq_record, cluster['idx'])
    if cluster_rec is None:
        return sidepanel

    if sidepanel is None:
        sidepanel = pq('<div>')
        sidepanel.addClass('sidepanel')

    core_peptides = _find_core_peptides(cluster_rec, seq_record)
    if len(core_peptides) == 0:
        return sidepanel

    details = pq('<div>')
    details.addClass('more-details')
    details_header = pq('<h3>')
    details_header.text('Prediction details')
    details.append(details_header)
    details_list = pq('<dl>')
    details_list.addClass('prediction-text')

    for cp in core_peptides:
        dt = pq('<dt>')
        dt.text(utils.get_gene_id(cp))
        details_list.append(dt)
        dd = pq('<dd>')
        thio_type = _get_core_peptide_type(cp)
        score = _get_core_peptide_score(cp)
        rodeo_score = _get_core_peptide_rodeo_score(cp)
        core_seq =  _get_core_peptide_sequence(cp)
        amidation = _get_core_peptide_tail_reaction(cp)
        mass = _get_monoisotopic_mass(cp) 
        mol_weight = _get_molecular_weight(cp)
        macrocycle = _get_macrocycle_size(cp)
        core_features =  _get_core_features(cp)
        alt_weights = _get_alternative_weights(cp)
        
        dd.html('Putative %s<br>Cleavage pHMM score: %0.2f<br>RODEO score: %i<br>Monoisotopic mass: %s Da<br>'\
                'Molecular weight: %s Da<br> Core sequence: %s<br>'
                '<u> Predicted peptide features:</u><br> %s<br>' %\
                (thio_type, score, rodeo_score, mass, mol_weight, core_seq, core_features))

             
        if macrocycle != '':
            dd.html('%s Macrocycle: %s<br>' % (dd.html(), macrocycle))

        if amidation != None:
            dd.html('%s Tail reaction: %s<br>' % (dd.html(),amidation))

        
        details_list.append(dd)  
        br = pq('<br>')
        details_list.append(br)
        dt = pq('<dt>')
        details_list.append(dt)
        dd = pq('<dd>')
        if thio_type != "Type III":
            dt.text('Considering maturation reactions')
            mature_mono_mass = _get_mature_mass(cp)
            mature_mol_weight = _get_mature_mw(cp)
            dd.html('Monoisotopic mass: %s Da<br>'\
                    'Molecular weight: %s Da<br>' %\
                    (mature_mono_mass, mature_mol_weight))

            alt_weights = _get_mature_alternative_weights(cp)
        if alt_weights:
            inner_dl = pq('<dl>')
            inner_dt = pq('<dt>')
            inner_dt.text('Alternative weights')
            inner_dl.append(inner_dt)
            inner_dd = pq('<dd>')
            inner_dd.addClass('alt-weight-desc')
            inner_dd.text('(assuming N unmodified Ser/Thr residues)')
            inner_dl.append(inner_dd)
            i = 1
            for weight in alt_weights:
                inner_dd = pq('<dd>')
                weight_span = pq('<span>')
                weight_span.text('%0.1f Da' % weight)
                weight_span.addClass('alt-weight')
                n_span = pq('<span>')
                n_span.text('N = %d' % i)
                n_span.addClass('alt-weight-n')
                inner_dd.append(weight_span)
                inner_dd.append(n_span)
                inner_dl.append(inner_dd)
                i += 1
            dd.append(inner_dl)
        details_list.append(dd)
        
    details.append(details_list)
    sidepanel.append(details)

    cross_refs = pq("<div>")
    refs_header = pq('<h3>')
    refs_header.text('Database cross-links')
    cross_refs.append(refs_header)
    links = pq("<div>")
    links.addClass('prediction-text')

    a = pq("<a>")
    a.attr('href', 'http://bioinfo.lifl.fr/norine/form2.jsp')
    a.attr('target', '_new')
    a.text("Look up in NORINE database")
    links.append(a)
    cross_refs.append(links)
    sidepanel.append(cross_refs)

    return sidepanel


def _find_core_peptides(cluster, seq_record):
    """Find CDS_motifs containing thiopeptide core peptide annotations"""
    motifs = []
    for motif in utils.get_all_features_of_type(seq_record, 'CDS_motif'):
        if motif.location.start < cluster.location.start or \
           motif.location.end > cluster.location.end:
            continue

        if not motif.qualifiers.has_key('note'):
            continue

        if not 'core peptide' in motif.qualifiers['note']:
            continue

        if not 'thiopeptide' in motif.qualifiers['note']:
            continue
        
        motifs.append(motif)

    return motifs

def _find_leader_peptides(cluster, seq_record):
    """Find CDS_motifs containing thiopeptide leader peptide annotations"""
    motifs = []
    for motif in utils.get_all_features_of_type(seq_record, 'CDS_motif'):
        if motif.location.start < cluster.location.start or \
           motif.location.end > cluster.location.end:
            continue

        if not motif.qualifiers.has_key('note'):
            continue

        if not 'leader peptide' in motif.qualifiers['note']:
            continue

        if not 'thiopeptide' in motif.qualifiers['note']:
            continue

        motifs.append(motif)

    return motifs

def _get_monoisotopic_mass(motif):
    """Get monoisotopic mass of a core peptide motif"""
    for note in motif.qualifiers['note']:
        if not note.startswith('monoisotopic mass:'):
            continue
        return float(note.split(':')[-1])

def _get_molecular_weight(motif):
    """Get molecular weight of a core peptide motif"""
    for note in motif.qualifiers['note']:
        if not note.startswith('molecular weight:'):
            continue
        return float(note.split(':')[-1])

def _get_alternative_weights(motif):
    """Get alternative weights assuming less Ser/Thr residues are dehydrated"""
    alternative_weights = []
    for note in motif.qualifiers['note']:
        if not note.startswith('alternative weights:'):
            continue
        weights = note.split(':')[-1].split(';')
        alternative_weights = map(lambda x: float(x), weights)
    return alternative_weights

def _get_leader_peptide_sequence(motif):
    """Get AA sequence of a core peptide motif"""
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted leader seq:'):
            continue
        return note.split(':')[-1].strip()

def _get_core_peptide_sequence(motif):
    """Get AA sequence of a core peptide motif"""
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted core seq:'):
            continue
        return note.split(':')[-1].strip()
    
def _get_core_peptide_type(motif):
    """Get the predicted type of the core peptide"""
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted type:'):
            continue
        return note.split(':')[-1].strip().replace('-', ' ')


def _get_core_peptide_score(motif):
    """Get the score of the core peptide prediction"""
    for note in motif.qualifiers['note']:
        if not note.startswith('score:'):
            continue
        return float(note.split(':')[-1].strip())

def _get_core_peptide_rodeo_score(motif):
    """Get the score of the core peptide prediction"""
    for note in motif.qualifiers['note']:
        if not note.startswith('RODEO score:'):
            continue
        return int(note.split(':')[-1].strip())

def _get_core_peptide_tail_reaction(motif):
    """Get the tail reaction of the core peptide"""
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted tail reaction:'):
            continue
        return note.split(':')[-1].strip()
             
def _get_macrocycle_size(motif):
    """ Get macrocycle from core peptide"""
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted macrocycle:'):
            continue
        return note.split(':')[-1].strip()

        
def _get_mature_alternative_weights(motif):
    """Get alternative weights considering maturation process"""
    mature_alt_weights = []
    for note in motif.qualifiers['note']:
        if not note.startswith('alternative weights considering maturation:'):
            continue
        weights = note.split(':')[-1].split(';')
        mature_alt_weights = map(lambda x: float(x), weights[2:])
    return mature_alt_weights

def _get_mature_mass(motif):
    """Get monoisotopic mass after maturation process"""
    aux = []
    mature_mono_mass = 0
    for note in motif.qualifiers['note']:
        if not note.startswith('alternative weights considering maturation:'):
            continue
        weights = (note.split(':')[-1].split(';'))
        aux = map(lambda x: float(x), weights)
        mature_mono_mass = aux[1]
    return mature_mono_mass

def _get_mature_mw(motif):
    """Get molecular weight after maturation process"""
    aux = []
    mature_weight = 0
    for note in motif.qualifiers['note']:
        if not note.startswith('alternative weights considering maturation:'):
            continue
        weights = (note.split(':')[-1].split(';'))
        aux = map(lambda x: float(x), weights)
        mature_weight = aux[0]
    return mature_weight

def _get_core_features(motif):
    """ Get mature core features """
    for note in motif.qualifiers['note']:
        if not note.startswith('predicted core features:'):
            continue
        core_features = "".join(note.split(':')[-1].strip().replace('-',':'))
    return core_features

def _get_tail_cut(motif):
    """Get putative C-terminal cleaved off residues from a core peptide"""
    for note in motif.qualifiers['note']:
        if not note.startswith('putative cleaved off residues:'):
            continue
        return note.split(':')[-1].strip()
