# $CVSHeader: pal8e/src/Compare_DSSP.py,v 1.5 2005/02/15 01:10:24 indraneel Rel $

import os

'''
DSSP assignment:
E beta strand
H alpha helix
T turn
S bend
G 3-10 helix
B short beta bridge
I pi helix
C random coil
X
'''

class Compare_Common:
    def get_lines(self, fname):
        if not os.path.isfile(fname): return []
        fh = file(fname)
        lines = fh.readlines()
        fh.close()
        return lines

    def report(self, peptides, tag, helix_type, strand_type):
        tags = []
        tags.append(tag+'_'+tag+'_only')
        tags.append(tag+'_pssd_only')
        tags.append(tag+'_pssd_only_H')
        tags.append(tag+'_pssd_only_E')
        peptides.initialise_tags(tags)
        total_residues = 0
        total_pssd_H = 0
        total_pssd_E = 0
        total_other_H = 0
        total_other_E = 0
        both_H = 0
        both_E = 0
        only_pssd_H = 0
        only_pssd_E = 0
        only_other_H = 0
        only_other_E = 0
        for peptide in peptides:
            for res in peptide:
                val = getattr(res, 'compare_'+tag)
                if val == None:
                    mess = 'no '+tag+' output for '+str(res)
                    self.logger.log('critical', mess)
                    continue
                total_residues += 1
                if res.H: total_pssd_H += 1
                if res.E: total_pssd_E += 1
                if val in helix_type: total_other_H += 1
                if val in strand_type: total_other_E += 1
                if res.H and val in helix_type: both_H += 1
                if res.E and val in strand_type: both_E += 1
                if res.H and val not in helix_type:
                    only_pssd_H += 1
                    setattr(res, tag+'_pssd_only', 1)
                    setattr(res, tag+'_pssd_only_H', 1)
                if res.E and val not in strand_type:
                    only_pssd_E += 1
                    setattr(res, tag+'_pssd_only', 1)
                    setattr(res, tag+'_pssd_only_E', 1)
                if val in helix_type and not res.H:
                    only_other_H += 1
                    setattr(res, tag+'_'+tag+'_only', 1)
                if val in strand_type and not res.E:
                    only_other_E += 1
                    setattr(res, tag+'_'+tag+'_only', 1)
        tag = tag.upper()
        line = tag+' comparison report for '+str(total_residues)+' residues:\n'
        lines = [line]
        lines += [tag+' total_pssd_H '+str(total_pssd_H)+'\n']
        lines += [tag+' total_pssd_E '+str(total_pssd_E)+'\n']
        lines += [tag+' total_other_H '+str(total_other_H)+'\n']
        lines += [tag+' total_other_E '+str(total_other_E)+'\n']
        lines += [tag+' both_H '+str(both_H)+'\n']
        lines += [tag+' both_E '+str(both_E)+'\n']
        lines += [tag+' only_pssd_H '+str(only_pssd_H)+'\n']
        lines += [tag+' only_pssd_E '+str(only_pssd_E)+'\n']
        lines += [tag+' only_other_H '+str(only_other_H)+'\n']
        lines += [tag+' only_other_E '+str(only_other_E)+'\n']
        return lines

class DSSP_Reader:
    def _get_sec_str_lines(self, fname):
        common = Compare_Common()
        lines = common.get_lines(fname)
        if not lines: return []
        for start in range(len(lines)):
            if lines[start][:5] == '  #  ':
                break
        start += 1
        lines = lines[start:]
        return lines

    ## Public methods

    def extract_secstr(self, fname):
        lines = self._get_sec_str_lines(fname)
        secstrdef = {}
        for line in lines:
            if line[13] == '!': continue
            chain = line[11]
            if not secstrdef.has_key(chain):
                secstrdef[chain] = {}
            id = line[6:10]
            id = int(id)
            icode = line[10]
            if not secstrdef[chain].has_key(id):
                secstrdef[chain][id] = {}
            secstr = line[16]
            if not secstrdef[chain][id].has_key(icode):
                secstrdef[chain][id][icode] = secstr
        return secstrdef

class DSSP:
    def __init__(self, conf, logger):
        self.conf = conf
        self.logger = logger
        structureID = conf.get('Input', 'structureID')
        dsspdir = conf.get('Compare', 'dsspdir')
        dssptail = conf.get('Compare', 'dssptail')
        self.fname = dsspdir + structureID + dssptail

    def _report(self, peptides):
        peptides.initialise_tags(['dssp_dssp_only', 'dssp_pssd_only', \
                                  'dssp_pssd_only_H', 'dssp_pssd_only_E'])
        helix_type = ['H','G','I']
        strand_type = ['E','B']
        total_residues = 0
        total_pssd_H = 0
        total_pssd_E = 0
        total_other_H = 0
        total_other_E = 0
        both_H = 0
        both_E = 0
        only_pssd_H = 0
        only_pssd_E = 0
        only_other_H = 0
        only_other_E = 0
        for peptide in peptides:
            for res in peptide:
                if res.compare_dssp == None:
                    mess = 'no dssp output for '+str(res)
                    self.logger.log('critical', mess)
                    continue
                total_residues += 1
                if res.H: total_pssd_H += 1
                if res.E: total_pssd_E += 1
                if res.compare_dssp in helix_type: total_other_H += 1
                if res.compare_dssp in strand_type: total_other_E += 1
                if res.H and res.compare_dssp in helix_type: both_H += 1
                if res.E and res.compare_dssp in strand_type: both_E += 1
                if res.H and res.compare_dssp not in helix_type:
                    only_pssd_H += 1
                    res.dssp_pssd_only = 1
                    res.dssp_pssd_only_H = 1
                if res.E and res.compare_dssp not in strand_type:
                    only_pssd_E += 1
                    res.dssp_pssd_only = 1
                    res.dssp_pssd_only_E = 1
                if res.compare_dssp in helix_type and not res.H:
                    only_other_H += 1
                    res.dssp_dssp_only = 1
                if res.compare_dssp in strand_type and not res.E:
                    only_other_E += 1
                    res.dssp_dssp_only = 1
        line = 'DSSP comparison report for '+str(total_residues)+' residues:\n'
        lines = [line]
        lines += ['DSSP total_pssd_H '+str(total_pssd_H)+'\n']
        lines += ['DSSP total_pssd_E '+str(total_pssd_E)+'\n']
        lines += ['DSSP total_other_H '+str(total_other_H)+'\n']
        lines += ['DSSP total_other_E '+str(total_other_E)+'\n']
        lines += ['DSSP both_H '+str(both_H)+'\n']
        lines += ['DSSP both_E '+str(both_E)+'\n']
        lines += ['DSSP only_pssd_H '+str(only_pssd_H)+'\n']
        lines += ['DSSP only_pssd_E '+str(only_pssd_E)+'\n']
        lines += ['DSSP only_other_H '+str(only_other_H)+'\n']
        lines += ['DSSP only_other_E '+str(only_other_E)+'\n']
        self.logger.log('compare', lines)

    ## Public Methods
    
    def compare(self, structure, peptides):
        reader = DSSP_Reader()
        secstrdef = reader.extract_secstr(self.fname)
        for peptide in peptides:
            chain = peptide[0].get_parent().id
            if secstrdef.has_key(chain):
                for res in peptide:
                    if secstrdef[chain].has_key(res.id[1]):
                        if secstrdef[chain][res.id[1]].has_key(res.id[2]):
                            v = secstrdef[chain][res.id[1]][res.id[2]]
                            res.compare_dssp = v
        self._report(peptides)
