001package org.biojava.nbio.structure.chem;
002
003import java.io.Serializable;
004import java.util.HashMap;
005import java.util.Map;
006
007/**
008 * Enumerates the possible classifications of residues. These are generally more specific than PolymerTypes
009 * This information is derived from the mmcif dictionary.
010 * @author mulvaney
011 * @author Andreas Prlic
012 * @see <a href="http://mmcif.rcsb.org/dictionaries/mmcif_pdbx.dic/Items/_chem_comp.type.html">link into mmCIF dictionary</a>
013 * @since 1.7
014 */
015public enum ResidueType implements Serializable {
016    atomn(null, "null"), // present in db for _chem_comp.id_ = 'CFL' but not enumerated in dictionary
017    // Peptides
018    dPeptideLinking(PolymerType.dpeptide, "D-peptide linking"),
019    lPeptideLinking(PolymerType.peptide, "L-peptide linking"),
020    glycine(PolymerType.peptide,"PEPTIDE LINKING"),
021    peptideLike(PolymerType.otherPolymer, "peptide-like"),
022    dPeptideAminoTerminus(PolymerType.dpeptide, "D-peptide NH3 amino terminus"),
023    lPeptideAminoTerminus(PolymerType.peptide, "L-peptide NH3 amino terminus"),
024    dPeptideCarboxyTerminus(PolymerType.dpeptide, "D-peptide COOH carboxy terminus"),
025    lPeptideCarboxyTerminus(PolymerType.peptide, "L-peptide COOH carboxy terminus"),
026    // Nucleotides
027    dnaLinking(PolymerType.dna, "DNA linking"),
028    rnaLinking(PolymerType.rna, "RNA linking"),
029    dna3PrimeTerminus(PolymerType.dna, "DNA OH 3 prime terminus"),
030    rna3PrimeTerminus(PolymerType.rna, "RNA OH 3 prime terminus"),
031    dna5PrimeTerminus(PolymerType.dna, "DNA OH 5 prime terminus"),
032    rna5PrimeTerminus(PolymerType.rna, "RNA OH 5 prime terminus"),
033    // Sugars
034    dSaccharide(PolymerType.polysaccharide, "D-saccharide"),
035    dSaccharide14and14linking(PolymerType.polysaccharide, "D-saccharide 1,4 and 1,4 linking"),
036    dSaccharide14and16linking(PolymerType.polysaccharide, "D-saccharide 1,4 and 1,6 linking"),
037    lSaccharide(PolymerType.lpolysaccharide, "L-saccharide"),
038    lSaccharide14and14linking(PolymerType.lpolysaccharide, "L-saccharide 1,4 and 1,4 linking"),
039    lSaccharide14and16linking(PolymerType.lpolysaccharide, "L-saccharide 1,4 and 1,6 linking"),
040    saccharide(PolymerType.polysaccharide, "saccharide"),
041    // Iso-peptides
042    dBetaPeptideCGammaLinking(PolymerType.dpeptide,"D-beta-peptide, C-gamma linking"),
043    dGammaPeptideCDeltaLinking(PolymerType.dpeptide,"D-gamma-peptide, C-delta linking"),
044    lBetaPeptideCGammaLinking(PolymerType.peptide,"L-beta-peptide, C-gamma linking"),
045    lGammaPeptideCDeltaLinking(PolymerType.peptide,"L-gamma-peptide, C-delta linking"),
046    // L nucleotides. As of 2015-04, these are only found in D-DNA hybrids, so they don't have their own PolymerType
047    lDNALinking(PolymerType.dna,"L-DNA linking"),
048    lRNALinking(PolymerType.dna,"L-RNA linking"),
049    // Other
050    nonPolymer(null, "non-polymer"),
051    otherChemComp(null, "other");
052
053    static Map<String, ResidueType> lookupTable = new HashMap<>();
054
055    static {
056        for (ResidueType residueType : ResidueType.values() ) {
057            lookupTable.put(residueType.chem_comp_type, residueType);
058            lookupTable.put(residueType.chem_comp_type.toLowerCase(), residueType);
059        }
060    }
061
062    ResidueType(PolymerType polymerType, String chem_comp_type) {
063        this.polymerType = polymerType;
064        this.chem_comp_type = chem_comp_type;
065    }
066
067    /**
068     * The associated {@link PolymerType}
069     */
070    public final PolymerType polymerType;
071
072    /**
073     * Gets the associated PolymerType, which are less specific
074     * @return
075     */
076    public PolymerType getPolymerType() {
077        return polymerType;
078    }
079
080    /**
081     * String value of the type
082     */
083    public final String chem_comp_type;
084
085    /** Get ResidueType by chem_comp_type
086     *
087     * @param chem_comp_type e.g. L-peptide linking
088     * @return
089     */
090    public static ResidueType getResidueTypeFromString(String chem_comp_type) {
091        if (chem_comp_type == null) {
092            return null;
093        }
094
095        // Almost all calls to this method are for L-peptide linking. Use this knowledge for a shortcut.
096        if (chem_comp_type.equalsIgnoreCase(lPeptideLinking.chem_comp_type)) {
097            return lPeptideLinking;
098        }
099
100        ResidueType lookedUpResidueType = lookupTable.get(chem_comp_type);
101        if (lookedUpResidueType != null) {
102            return lookedUpResidueType;
103        }
104
105        /*
106         * Unfortunately it can be guaranteed that chem_comp_type case sensitivity is preserved.
107         * E.g. mmtf has it all upper-case. As such we need to do a second check
108         */
109        lookedUpResidueType = lookupTable.get(chem_comp_type.toLowerCase());
110        if (lookedUpResidueType != null) {
111            return lookedUpResidueType;
112        }
113
114        // preserving previous behaviour. Not sure if this is really necessary?
115        for (ResidueType residueType : ResidueType.values()) {
116            if(residueType.chem_comp_type.equalsIgnoreCase(chem_comp_type)) {
117                return residueType;
118            }
119
120            if (residueType.chem_comp_type.toLowerCase().startsWith(chem_comp_type.toLowerCase())) {
121                return residueType;
122            }
123            if (chem_comp_type.toLowerCase().startsWith(residueType.chem_comp_type.toLowerCase())) {
124                return residueType;
125            }
126        }
127        return null;
128    }
129}