# $CVSHeader: pal8e/src/DSSPStat.py,v 1.3 2005/02/15 01:10:25 indraneel Rel $

from CoordCalc import distance, torsion, v_angle
import DSSPQuad

class DSSPStat:
    def d3(self, element, dataArray):
        for (i,residue) in enumerate(element[:-3]):
            d3 = distance(residue.coord, element[i+3].coord)
            dataArray.append(d3)

    def dih(self, element, dataArray):
        for (i,residue) in enumerate(element[:-3]):
            dih = torsion(residue.coord, element[i+1].coord,
                          element[i+2].coord, element[i+3].coord)
            dataArray.append(dih)

    def orient(self, resa, resb, shim):
        if resa.mol[resa.chain].has_key(resa.resid + 1):
            resaNext = resa.mol[resa.chain][resa.resid + 1]
        else: return False
        if resb.mol[resb.chain].has_key(resb.resid + shim):
            resbNext = resb.mol[resb.chain][resb.resid + shim]
        else: return False
        if resaNext in resbNext.pairs:
            return True
        return False

    def getOrient(self, resa, resb):
        if self.orient(resa, resb, 1): return 'Syn'
        if self.orient(resa, resb, -1): return 'Anti'
        return None

    def getDists(self, element, orient):
        dists = []
        for (i,res) in enumerate(element[:-1]):
            for pair in ['pair1', 'pair2']:
                if (hasattr(res, pair) and
                    (res.resid < getattr(res, pair).resid)):
                    if self.getOrient(res, getattr(res, pair)) == orient:
                        dists.append(distance(res.coord,
                                              getattr(res, pair).coord))
        return dists

    def synDist(self, element, dataArray):
        data = self.getDists(element, 'Syn')
        dataArray += data

    def antiDist(self, element, dataArray):
        data = self.getDists(element, 'Anti')
        dataArray += data

    def getAngleData(self, element, orient, parmType):
        data = []
        if len(element) < 3: return []
        for (i,res) in enumerate(element[1:-1]):
            c = i+1
            for pair in ['pair1', 'pair2']:
                if not (hasattr(element[c-1], pair) and
                        hasattr(res, pair) and
                        hasattr(element[c+1], pair)): continue
                prev = getattr(element[c-1], pair)
                this = getattr(res, pair)
                next = getattr(element[c+1], pair)
                if element[c].resid > this.resid: continue
                if res==this: continue
                if ((prev.resid == 0) or
                    (this.resid == 0) or
                    (next.resid == 0)): continue
                if element[c-1] not in prev.pairs: continue
                if res not in this.pairs: continue
                if element[c+1] not in next.pairs: continue
                if (abs(prev.resid-this.resid)>1 or
                    abs(this.resid-next.resid)>1): continue
                if (prev.resid - this.resid) > 0: _orient = 'Anti'
                else: _orient = 'Syn'
                # print element[c-1].resid, element[c].resid, element[c+1].resid, prev.resid, this.resid, next.resid, _orient
                if orient != _orient: continue
                if parmType == 'Bond':
                    bondAngle=v_angle((element[c-1].coord-element[c+1].coord),
                                      (res.coord-this.coord), 90)
                    #if (bondAngle<60):
                        #print 'bond', element[c-1].resid, element[c].resid, element[c+1].resid, prev.resid, this.resid, next.resid, _orient, bondAngle
                    data.append(bondAngle)
                    bondAngle=v_angle((prev.coord-next.coord),
                                      (this.coord-res.coord), 90)
                    #if (bondAngle<60):
                        #print 'bond', element[c-1].resid, element[c].resid, element[c+1].resid, prev.resid, this.resid, next.resid, _orient, bondAngle
                    data.append(bondAngle)
                elif parmType == 'Tor':
                    #print res.resid, ' ', this.resid
                    #print element[c-1].coord, res.coord, element[c+1].coord
                    #print prev.coord, this.coord, next.coord
                    torAngle=torsion(res.coord,
                                     (element[c-1].coord+element[c+1].coord)/2,
                                     (prev.coord+next.coord)/2, this.coord)
                    #if ((torAngle<-160) or (torAngle>160)):
                        #print 'tor', element[c-1].resid, element[c].resid, element[c+1].resid, prev.resid, this.resid, next.resid, _orient, torAngle
                    data.append(torAngle)
        return data

    def synBond(self, element, dataArray):
        data = self.getAngleData(element, 'Syn', 'Bond')
        dataArray += data

    def antiBond(self, element, dataArray):
        data = self.getAngleData(element, 'Anti', 'Bond')
        dataArray += data

    def synTor(self, element, dataArray):
        data = self.getAngleData(element, 'Syn', 'Tor')
        dataArray += data

    def antiTor(self, element, dataArray):
        data = self.getAngleData(element, 'Anti', 'Tor')
        dataArray += data

    def getQuadData(self, element, orient):
        data = []
        if len(element) < 6: return []
        for (i,res) in zip(range(len(element)),element)[2:-3]:
            for pair in ['pair1', 'pair2']:
                brk=0
                pairs = [0,0,0,0,0,0]
                for j in range(-2,4):
                    if not (hasattr(element[i+j], pair)):
                        brk = 1
                        break
                    else:
                        pairs[j+2] = getattr(element[i+j], pair)
                if brk: continue
                if res.resid >= pairs[2].resid: continue
                for j in range(-2,3):
                    if ( (abs(element[i+j+1].resid-element[i+j].resid)>1) or
                         (abs(pairs[j+2+1].resid-pairs[j+2].resid)>1) ):
                        brk = 1
                        break
                if brk: continue
                # here we have a ladder of at least 6 residues
                if (pairs[2].resid - pairs[3].resid) > 0: _orient = 'Anti'
                else: _orient = 'Syn'
                if orient != _orient: continue
                #send 4+4 residues to DSSPQuad to obtain score
                quad = DSSPQuad.DSSPQuad()
                GQscore = quad.score(element[i-1], pairs[1],
                                     element[i], pairs[2],
                                     element[i+1], pairs[3],
                                     element[i+2], pairs[4],
                                     orient, 'Good'+orient)
                if GQscore == 'Err':
                    return []
                BQscores=[0,0,0,0]
                BQscores[0] = quad.score(element[i-2],pairs[1],
                                         element[i-1], pairs[2],
                                         element[i], pairs[3],
                                         element[i+1], pairs[4],
                                         orient, 'Bad'+orient)
                BQscores[1] = quad.score(element[i], pairs[1],
                                         element[i+1], pairs[2],
                                         element[i+2], pairs[3],
                                         element[i+3], pairs[4],
                                         orient, 'Bad'+orient)
                BQscores[2] = quad.score(element[i-1], pairs[0],
                                         element[i], pairs[1],
                                         element[i+1], pairs[2],
                                         element[i+2], pairs[3],
                                         orient, 'Bad'+orient)
                BQscores[3] = quad.score(element[i-1], pairs[2],
                                         element[i], pairs[3],
                                         element[i+1], pairs[4],
                                         element[i+2], pairs[5],
                                         orient, 'Bad'+orient)
                BQscore = min(BQscores)
                if BQscore == 'Err':
                    return []
                data = [[GQscore, BQscore]]
        return data

    def synQuad(self, element, dataArray):
        data = self.getQuadData(element, 'Syn')
        dataArray += data

    def antiQuad(self, element, dataArray):
        data = self.getQuadData(element, 'Anti')
        dataArray += data

    def i2Angle(self, element, dataArray):
        if len(element) < 6: return [] # minimum 6 for bulge
        for (i,res) in zip(range(len(element)),element)[2:-2]:
            for pair in ['pair1', 'pair2']:
                brk=0
                pairs = [0,0,0,0,0]
                for j in range(-2,3):
                    if not (hasattr(element[i+j], pair)):
                        brk = 1
                        break
                    else:
                        pairs[j+2] = getattr(element[i+j], pair)
                if brk: continue
                if res.resid >= pairs[2].resid: continue
                for j in range(-2,2):
                    if ( (abs(element[i+j+1].resid-element[i+j].resid)>1) or
                         (abs(pairs[j+2+1].resid-pairs[j+2].resid)>1) ):
                        brk = 1
                        break
                if brk: continue
                # here we have a ladder of at least 5 residues
                i2angle=v_angle((element[i-2].coord-res.coord),
                                (res.coord-element[i+2].coord), 180)
                dataArray.append(i2angle)
        
    def i4pseudoAngle(self, element, dataArray):
        if len(element) < 6: return [] # minimum 6 for bulge
        for (i,res) in zip(range(len(element)),element)[2:-3]:
            for pair in ['pair1', 'pair2']:
                brk=0
                pairs = [0,0,0,0,0,0]
                for j in range(-2,4):
                    if not (hasattr(element[i+j], pair)):
                        brk = 1
                        break
                    else:
                        pairs[j+2] = getattr(element[i+j], pair)
                if brk: continue
                if res.resid >= pairs[2].resid: continue
                for j in range(-2,3):
                    if ( (abs(element[i+j+1].resid-element[i+j].resid)>1) or
                         (abs(pairs[j+2+1].resid-pairs[j+2].resid)>1) ):
                        brk = 1
                        break
                if brk: continue
                # here we have a ladder of at least 6 residues
                vCAcoord = (element[i-1].coord + \
                            res.coord + \
                            element[i+1].coord + \
                            element[i+2].coord) / 4
                i4pseudoAngle=v_angle((element[i-2].coord-vCAcoord),
                                      (vCAcoord-element[i+3].coord), 180)
                dataArray.append(i4pseudoAngle)

    def Q120Angle(self, element, dataArray):
        if len(element) < 4: return []
        for (i,res) in zip(range(len(element)),element)[1:-1]:
            pair = [[0,0,0],
                    [0,0,0],
                    [0,0,0]]
            brk = 0
            for j in range(-1,2):
                if not ( hasattr(element[i+j], 'pair1') and
                         hasattr(element[i+j], 'pair2') ):
                    brk = 1
                    break
            if brk: continue
            angle = v_angle((res.pair1.coord-res.coord),
                            (res.pair2.coord-res.coord))
            dataArray.append(angle)
