import os
from inmembrane.helpers import dict_get, chop_nterminal_peptide, log_stderr


def get_annotations(params):
    annotations = []
    params['signalp4_organism'] = 'gram-'

    if not params['signalp4_bin'] or params[
        'signalp4_bin'] == 'signalp_scrape_web':
        annotations += ['signalp_scrape_web']
    else:
        annotations += ['signalp4']

    if not params['lipop1_bin'] or params['lipop1_bin'] == 'lipop_scrape_web':
        annotations += ['lipop_scrape_web']
    else:
        annotations += ['lipop1']

    annotations += ['tatfind_web']

    if 'bomp' in dict_get(params, 'barrel_programs'):
        annotations.append('bomp_web')
    # DEPRECATED: TMB-HUNT server is permanently offline
    # if 'tmbhunt' in dict_get(params, 'barrel_programs'):
    #  annotations.append('tmbhunt_web')
    if 'tmbetadisc-rbf' in dict_get(params, 'barrel_programs'):
        annotations.append('tmbetadisc_rbf_web')

    if dict_get(params, 'helix_programs'):
        if 'tmhmm' in params['helix_programs']:
            if not params['tmhmm_bin'] or \
                    params['tmhmm_bin'] == 'tmhmm_scrape_web':
                annotations.append('tmhmm_scrape_web')
            else:
                annotations.append('tmhmm')
        if 'memsat3' in params['helix_programs']:
            annotations.append('memsat3')

    # run some hmm profiles to detect features (eg Tat signal)
    annotations += ['hmmsearch3']
    params['hmm_profiles_dir'] = os.path.join(
        os.path.dirname(__file__), 'gram_neg_profiles')

    return annotations


def post_process_protein(params, protein):
    def has_tm_helix(protein):
        for program in params['helix_programs']:
            if dict_get(protein, '%s_helices' % program):
                return True
        return False

    # these functions detect if and TM-containing IM proteins
    # have large loops / terminal regions in the periplasm or cytoplasm
    # that may be accessible / inaccessible in spheroplast shaving
    # experiments.
    def has_long_loops(protein, loop_str='_outer_loops', \
                       loop_length=params['internal_exposed_loop_min']):
        for annot in protein:
            if loop_str in annot:
                for loop in protein[annot]:
                    l_len = loop[1] - loop[0]
                    if l_len >= loop_length:
                        return True
        return False

    def long_in_periplasm(protein, \
                          loop_length=params['internal_exposed_loop_min']):
        return has_long_loops(protein, '_outer_loops', loop_length)

    def long_in_cytoplasm(protein, \
                          loop_length=params['internal_exposed_loop_min']):
        return has_long_loops(protein, '_inner_loops', loop_length)

    details = []
    category = "UNKNOWN"
    is_hmm_profile_match = dict_get(protein, 'hmmsearch')
    is_signalp = dict_get(protein, 'is_signalp')
    is_tatfind = dict_get(protein, 'is_tatfind')
    is_lipop = dict_get(protein, 'is_lipop')

    # in terms of most sublocalization logic, a Tat signal is similar to a
    # Sec (signalp) signal. We use has_signal_pept to denote that either
    # is present.
    has_signal_pept = False
    if is_signalp or is_tatfind or \
            (('hmmsearch' in protein) and "Tat_PS51318" in protein[
                'hmmsearch']):
        has_signal_pept = True

    # annotate the barrels - high scoring bomp hits don't require a
    # signal peptide, low scoring ones do
    has_barrel = False
    bomp_score = dict_get(protein, 'bomp')
    if (bomp_score >= params['bomp_clearly_cutoff']) or \
            (has_signal_pept and bomp_score >= params['bomp_maybe_cutoff']):
        details += ['bomp(%i)' % (bomp_score)]
        has_barrel = True

    # DEPRECATED: TMB-HUNT server is permanently offline
    # tmbhunt_prob = dict_get(protein, 'tmbhunt_prob')
    # if (tmbhunt_prob >= params['tmbhunt_clearly_cutoff']) or \
    #   (has_signal_pept and tmbhunt_prob >= params['tmbhunt_maybe_cutoff']):
    #  details += ['tmbhunt(%.2f)' % (tmbhunt_prob)]
    #  has_barrel = True

    if has_signal_pept and dict_get(protein, 'is_tmbetadisc_rbf'):
        details += ['tmbetadisc-rbf']
        has_barrel = True

    if has_barrel:
        category = 'OM(barrel)'

    # we only regard the barrel prediction as a true positive
    # if a signal peptide is also present
    #  is_barrel = False
    #  if has_signal_pept and has_barrel: # TODO and num_tms <= 1:
    #    category = 'OM(barrel)'
    #    is_barrel = True

    # set number of predicted OM barrel strands in details
    if has_barrel and \
            dict_get(protein, 'tmbeta_strands'):
        num_strands = len(protein['tmbeta_strands'])
        details += ['tmbeta_strands(%i)' % (num_strands)]

    if has_signal_pept and not is_lipop and \
            (dict_get(protein, 'signalp_cleave_position')):
        # we use the SignalP signal peptidase cleavage site for Tat signals
        chop_nterminal_peptide(protein, protein['signalp_cleave_position'])

    if is_tatfind:
        details += ["tatfind"]

    if is_signalp:
        details += ["signalp"]

    if is_lipop:
        details += ["lipop"]
        chop_nterminal_peptide(protein, protein['lipop_cleave_position'])

    if is_hmm_profile_match:
        details += ["hmm(%s)" % "|".join(protein['hmmsearch'])]

    if has_tm_helix(protein) and not has_barrel:
        for program in params['helix_programs']:
            n = len(protein['%s_helices' % program])
            details += [program + "(%d)" % n]

        category = "IM"
        if long_in_periplasm(protein):
            category += "+peri"
        if long_in_cytoplasm(protein):
            category += "+cyto"
    elif not has_barrel:
        if is_lipop:
            if dict_get(protein, 'lipop_im_retention_signal'):
                category = "LIPOPROTEIN(IM)"
            else:
                category = "LIPOPROTEIN(OM)"
            pass
        elif (has_signal_pept):
            category = "PERIPLASMIC/SECRETED"
        else:
            category = "CYTOPLASM"

    if details == []:
        details = ["."]

    protein['details'] = details
    protein['category'] = category

    return details, category


def protein_output_line(seqid, proteins):
    return '%-15s   %-13s  %-50s  %s' % \
           (seqid,
            proteins[seqid]['category'],
            ";".join(proteins[seqid]['details']),
            proteins[seqid]['name'][:60])


def protein_csv_line(seqid, proteins):
    return '%s,%s,%s,"%s"\n' % \
           (seqid,
            proteins[seqid]['category'],
            ";".join(proteins[seqid]['details']),
            proteins[seqid]['name'])


def summary_table(params, proteins):
    """
    Returns a string representing a simple summary table of
    protein classifcations.
    """
    out = ""
    counts = {}
    for seqid in proteins:
        category = proteins[seqid]['category']

        if category not in counts:
            counts[category] = 1
        else:
            counts[category] += 1

    out += "\n\n# Number of proteins in each class:\n"
    for c in counts:
        out += "# %-15s %i\n" % (c, counts[c])

    return out
