# eds
# 
# Reads an RDS file and keeps some data (esp. RSCC).
#
# Author       : Chris X. Weichenberger
# Created      : 2010-11-23
# License
# Twilight is a GUI for displaying ligands incompatible with electron density.
#    Copyright (C) 2012  Christian X. Weichenberger, Edwin Pozharski, and
#    Bernhard Rupp.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Modifications:
# YYYY-MM-DD (WHO) what
#
# known bugs:
#
#

import os;
import re;
import sys;
import string;
from misc import EDSDIR, ReadTextFile, STDAMINOS, NONLIGANDS;


EDSRESNMIDX = 0; # residue name
EDSRSCCIDX  = 1; # rscc 
EDSOWABIDX  = 2; # occupany weighted average B factor

class CEDS(dict):
    """Acts like a cache."""
    def __getitem__(s, pdbCode):
        """Key is a PDB four letter code, value is a dictionary (key: rnr,
        value: (resnm, rscc) )"""
        if( pdbCode not in s ):
            edsf = CEDSFile();
            edsf.parse(pdbCode);
            s[pdbCode] = {}
            if( edsf.has_features() ):
                for rnr, value in edsf.items():
                    s[pdbCode][rnr] = value;
        return dict.__getitem__(s, pdbCode);


class CEDSFile(dict):
    def __init__(s):
        dict.__init__(s);
        s.FileFound = False;
    
    def __str__(s):
        # a key is a residue number with chain name.
        keys = s.keys();
        keys.sort();
        lst  = ["%s,%s\t%s\t%s\t%4.3f" % \
                  (s.PDBCode,k[0], k, s[k][EDSRESNMIDX], s[k][EDSRSCCIDX])\
                  for k in keys];
        return string.join(lst, "\n");
    
    def parse(s, pdbCode="", pdbFFN=""):
        """Read an EDS file.
        """
        if( pdbCode!="" ):
            s.PDBCode = pdbCode;
            ffn = os.path.join(EDSDIR, pdbCode + "_stat.lis");
        else:
            s.PDBCode = "????";
            ffn = pdbFFN;
        lines = ReadTextFile(ffn);
        if( lines!=None and len(lines)!=0 ):
            s.FileFound = True;
            for line in lines:
                if( line[0]!="!" ):
                    resNm = line[8:11].strip();
                    if( resNm in NONLIGANDS ): continue ;
                    rnr   = line[12:18];
                    owab  = float(line[34:39]);
                    chnNm = rnr[0];
                    rscc  = float(line[19:26]);
                    s[rnr]= (resNm, rscc, owab);

    def has_features(s):
        return s.FileFound;

    def is_valid(s, pdbFFN):
        """Implements some simple heuristics whether this is a valid EDS Stat
        List file. 
        @return @c True or @c False.
        """
        # There should be a line like
        # ! Created by MAPMAN V. 080625/7.8.5 at Mon Jun 8 22:36:34 2009 [...]
        # We will look for this in the first couple of lines.
        readAhead = 10;
        fh        = open(pdbFFN);
        i         = 1;
        for line in fh:
            if( re.search("^!.*MAPMAN", line) ):
                return True;
            i += 1;
            if( i>readAhead ):
                break ;
        return False;
            
        
def Usage():
    print """Usage %s -f pdbcode
 where  -f Parses and prints an EDS file.""" % \
    (os.path.basename(sys.argv[0]), );
    
if( __name__=="__main__" ):
    if( len(sys.argv) not in (2,3) ):
        Usage();
        sys.exit(1);
    if( sys.argv[1] not in ("-f", ) ):
        Usage();
        sys.exit(1);
        
    if( sys.argv[1]=="-f" ):
        edsf = CEDSFile();
        edsf.parse(sys.argv[2]);
        if( edsf.has_features() ):
            print edsf
