# Ligand data container.
#
# Author       : Chris X. Weichenberger
# Created      : 2012-07-26
# 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:
#  2012-08-02 (CW)  Computation of ligand molecular weight.

NOTHING           = "-";
ISBUFFERMOLECULE  = "B";
ISLPEPTIDE        = "P";

import sys

from misc import ReadTextFile, LPETIDESFN, BUFFERNMFN, NOVALIDFLOATSTR;
from chemform import CChemicalFormulaData;
from elements import GetPeriodicTable;


__PEPLIST = ReadTextFile(LPETIDESFN);
__BUFLIST = ReadTextFile(BUFFERNMFN);

def IsPeptide(nm):
    if( nm in __PEPLIST ):
        return ISLPEPTIDE;
    return NOTHING;


def IsBufferMolecule(nm):
    if( nm in __BUFLIST ):
        return ISBUFFERMOLECULE;
    return NOTHING;


def clsOR(c1, c2):
    """Performs logical OR on two classification codes."""
    if( c1==NOTHING and c2==NOTHING ):
        return NOTHING;
    elif( c1==NOTHING ):
        return c2;
    elif( c2==NOTHING ):
        return c1;
    # now, neither of them is NOTHING.
    elif( c1 in (ISION,ISCHARGEDMOLECULE) ):
        return c2;
    elif( c2 in (ISION,ISCHARGEDMOLECULE) ):
        return c1;
    else:
        sys.stderr.write("ligand.py: Uuups. Total confusion. Please report.");
        # We should exit here.
        return c1;


class CLigand:
    def __init__(s):
        s._LigName = "N/A";
        s._ResNr   = "N/A";
        s._RSCC    = float(NOVALIDFLOATSTR);
        s._OWAB    = float(NOVALIDFLOATSTR);
        s._MolWt   = float(NOVALIDFLOATSTR);
        s._ChemForm = CChemicalFormulaData("");
        
    def __str__(s):
        return "%s(%s) RSCC: %s OWAB: %s" %\
               (s._ResNr, s._LigName, s._RSCC, s._OWAB);

    def Set3LetterName(s, val):
        s._LigName = val;
        # Assign the classification code.
        s._ClsCode = clsOR(NOTHING, IsPeptide(s._LigName));
        s._ClsCode = clsOR(s._ClsCode, IsBufferMolecule(s._LigName));
    
    def SetResNr(s, val):
        s._ResNr = val;
    
    def SetRSCC(s, val):
        s._RSCC = float(val);

    def SetOWAB(s, val):
        s._OWAB = float(val);

    def SetMolWt(s, val):
        s._MolWt = float(val);
    
    def SetCombinedScore(s, val):
        s._Score = float(val);
    
    def SetChemFormula(s, formula):
        s._ChemForm = CChemicalFormulaData(formula);

    def ComputeMolWeight(s):
        """Compute the molecular mass of this ligand. (More or less.)
        If an unknown chemical element is encountered, the reported molecular
        weight is set to @c NOVALIDFLOATSTR.
        @return Molecular mass suitable for SetMoWt().
        """
        weight = 0.0;
        for sym, nr in s._ChemForm:
            elem = GetPeriodicTable().get(sym, None);
            if( elem!=None ):
                weight += nr * elem.GetWeight();
            else:
                sys.stderr.write("Unknown chemical element: ``%s''.\n" % sym);
                return float(NOVALIDFLOATSTR);
        return weight;
    
    def Get3LetterName(s):
        """@return @c String """
        return s._LigName;
    
    def GetResNr(s):
        """@return @c String """
        return s._ResNr;
    
    def GetRSCC(s):
        """@return @c Float """
        return s._RSCC;

    def GetOWAB(s):
        """@return @c Float """
        return s._OWAB;

    def GetMolWt(s):
        """@return @c Float """
        return s._MolWt;
    
    def GetCombinedScore(s):
        return s._Score;
    
    def GetClassification(s):
        """@return @c String """
        return s._ClsCode;
    
    def GetCharge(s):
        """@return @c Int """
        return s._ChemForm.getCharge();

    def GetNrHeavyAtoms(s):
        """@return @c Int """
        return s._ChemForm.nrHeavyAtoms();
        
    def GetNrHydrogenAtoms(s):
        """@return @c Int """
        return s._ChemForm.nrHydrogenAtoms();

    def GetNrAtoms(s):
        """@return @c Int """
        return s._ChemForm.nrAtoms();
    
if( __name__=="__main__" ):
    lig = CLigand();
    lig.Set3LetterName("IPA");
    lig.SetChemFormula("  2(C3 H8 O)    ");
    print lig.ComputeMolWeight();
