import os
from schrodinger.infra import canvas
from schrodinger.utils import fileutils
from . import common
RESIDUE_ATOM_TYPES = {}
# standard amino-acids
RESIDUE_ATOM_TYPES['ALA '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3'
}
RESIDUE_ATOM_TYPES['ARG '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' CD ': 'C.3',
    ' NE ': 'N.pl3',
    ' CZ ': 'C.cat',
    ' NH1': 'N.pl3',
    ' NH2': 'N.pl3'
}
RESIDUE_ATOM_TYPES['ASP '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.2',
    ' OD1': 'O.co2',
    ' OD2': 'O.co2'
}
RESIDUE_ATOM_TYPES['ASH '] = RESIDUE_ATOM_TYPES['ASP ']
RESIDUE_ATOM_TYPES['ASX '] = RESIDUE_ATOM_TYPES['ASP ']
RESIDUE_ATOM_TYPES['ASN '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.2',
    ' OD1': 'O.2',
    ' ND2': 'N.am'
}
RESIDUE_ATOM_TYPES['CYS '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' SG ': 'S.3'
}
RESIDUE_ATOM_TYPES['GLU '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' CD ': 'C.2',
    ' OE1': 'O.co2',
    ' OE2': 'O.co2'
}
RESIDUE_ATOM_TYPES['GLH '] = RESIDUE_ATOM_TYPES['GLU ']
RESIDUE_ATOM_TYPES['GLX '] = RESIDUE_ATOM_TYPES['GLU ']
RESIDUE_ATOM_TYPES['GLN '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' CD ': 'C.2',
    ' OE1': 'O.2',
    ' NE2': 'N.am'
}
RESIDUE_ATOM_TYPES['GLY '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2'
}
RESIDUE_ATOM_TYPES['HIS '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.ar',
    ' ND1': 'N.his',
    ' CD2': 'C.ar',
    ' CE1': 'C.ar',
    ' NE2': 'N.his'
}
RESIDUE_ATOM_TYPES['HID '] = RESIDUE_ATOM_TYPES['HIS ']
RESIDUE_ATOM_TYPES['HIE '] = RESIDUE_ATOM_TYPES['HIS ']
RESIDUE_ATOM_TYPES['HIP '] = RESIDUE_ATOM_TYPES['HIS ']
RESIDUE_ATOM_TYPES['HIX '] = RESIDUE_ATOM_TYPES['HIS ']
RESIDUE_ATOM_TYPES['ILE '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG1': 'C.3',
    ' CG2': 'C.3',
    ' CD1': 'C.3'
}
RESIDUE_ATOM_TYPES['LEU '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' CD1': 'C.3',
    ' CD2': 'C.3'
}
RESIDUE_ATOM_TYPES['LYS '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' CD ': 'C.3',
    ' CE ': 'C.3',
    ' NZ ': 'N.4'
}
RESIDUE_ATOM_TYPES['LYN '] = RESIDUE_ATOM_TYPES['LYS ']
RESIDUE_ATOM_TYPES['LYX '] = RESIDUE_ATOM_TYPES['LYS ']
RESIDUE_ATOM_TYPES['MET '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3',
    ' SD ': 'S.3',
    ' CE ': 'C.3'
}
RESIDUE_ATOM_TYPES['PHE '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.ar',
    ' CD1': 'C.ar',
    ' CD2': 'C.ar',
    ' CE1': 'C.ar',
    ' CE2': 'C.ar',
    ' CZ ': 'C.ar'
}
RESIDUE_ATOM_TYPES['PRO '] = {
    ' CD ': 'C.3',
    ' N  ': 'N.3',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.3'
}
RESIDUE_ATOM_TYPES['SER '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' OG ': 'O.3'
}
RESIDUE_ATOM_TYPES['THR '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' OG1': 'O.3',
    ' CG2': 'C.3'
}
RESIDUE_ATOM_TYPES['TRP '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.ar',
    ' CD1': 'C.ar',
    ' CD2': 'C.ar',
    ' NE1': 'N.am',
    ' CE2': 'C.ar',
    ' CE3': 'C.ar',
    ' CZ2': 'C.ar',
    ' CZ3': 'C.ar',
    ' CH2': 'C.ar'
}
RESIDUE_ATOM_TYPES['TYR '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG ': 'C.ar',
    ' CD1': 'C.ar',
    ' CD2': 'C.ar',
    ' CE1': 'C.ar',
    ' CE2': 'C.ar',
    ' CZ ': 'C.ar',
    ' OH ': 'O.3'
}
RESIDUE_ATOM_TYPES['VAL '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3',
    ' C  ': 'C.2',
    ' O  ': 'O.2',
    ' CB ': 'C.3',
    ' CG1': 'C.3',
    ' CG2': 'C.3'
}
# capping groups
RESIDUE_ATOM_TYPES['ACE '] = {
    ' C  ': 'C.2',
    ' CH3': 'C.3',
    ' O  ': 'O.2'
} # yapf: disable
RESIDUE_ATOM_TYPES['NMA '] = {
    ' N  ': 'N.am',
    ' CA ': 'C.3'
} # yapf: disable
for residue in RESIDUE_ATOM_TYPES.values():
    residue[' OXT'] = 'O.co2'
# DNA
RESIDUE_ATOM_TYPES[' DA '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' C1\'': 'C.3',
    ' N9 ': 'N.ar',
    ' C8 ': 'C.ar',
    ' N7 ': 'N.ar',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar',
    ' N6 ': 'N.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES[' DG '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' C1\'': 'C.3',
    ' N9 ': 'N.ar',
    ' C8 ': 'C.ar',
    ' N7 ': 'N.ar',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar',
    ' O6 ': 'O.2',
    ' N1 ': 'N.am',
    ' C2 ': 'C.ar',
    ' N2 ': 'N.3',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES[' DT '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' C1\'': 'C.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' O2 ': 'O.2',
    ' N3 ': 'N.am',
    ' C4 ': 'C.ar',
    ' O4 ': 'O.2',
    ' C5 ': 'C.ar',
    ' C7 ': 'C.3',
    ' C6 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES[' DC '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' C1\'': 'C.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' O2 ': 'O.2',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar',
    ' N4 ': 'N.3',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar'
} # yapf: disable
# RNA
RESIDUE_ATOM_TYPES['  A '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' O2\'': 'O.3',
    ' C1\'': 'C.3',
    ' N9 ': 'N.ar',
    ' C8 ': 'C.ar',
    ' N7 ': 'N.ar',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar',
    ' N6 ': 'N.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES['  U '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' O2\'': 'O.3',
    ' C1\'': 'C.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' O2 ': 'O.2',
    ' N3 ': 'N.am',
    ' C4 ': 'C.ar',
    ' O4 ': 'O.2',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES['  G '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' O2\'': 'O.3',
    ' C1\'': 'C.3',
    ' N9 ': 'N.ar',
    ' C8 ': 'C.ar',
    ' N7 ': 'N.ar',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar',
    ' O6 ': 'O.2',
    ' N1 ': 'N.am',
    ' C2 ': 'C.ar',
    ' N2 ': 'N.3',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES['  C '] = {
    ' P  ': 'P.3',
    ' OP1': 'O.co2',
    ' OP2': 'O.co2',
    ' O5\'': 'O.3',
    ' C5\'': 'C.3',
    ' C4\'': 'C.3',
    ' O4\'': 'O.3',
    ' C3\'': 'C.3',
    ' O3\'': 'O.3',
    ' C2\'': 'C.3',
    ' O2\'': 'O.3',
    ' C1\'': 'C.3',
    ' N1 ': 'N.ar',
    ' C2 ': 'C.ar',
    ' O2 ': 'O.2',
    ' N3 ': 'N.ar',
    ' C4 ': 'C.ar',
    ' N4 ': 'N.3',
    ' C5 ': 'C.ar',
    ' C6 ': 'C.ar'
} # yapf: disable
RESIDUE_ATOM_TYPES['HEM '] = {
    'FE  ': 'm.2',   # m = metal, 2 means +2 charge
    ' CHA': 'C.ar',
    ' CHB': 'C.ar',
    ' CHC': 'C.ar',
    ' CHD': 'C.ar',
    ' NA ': 'N.ar',
    ' C1A': 'C.ar',
    ' C2A': 'C.ar',
    ' C3A': 'C.ar',
    ' C4A': 'C.ar',
    ' CMA': 'C.3',
    ' CAA': 'C.3',
    ' CBA': 'C.3',
    ' CGA': 'C.2',
    ' O1A': 'O.2',
    ' O2A': 'O.co2',
    ' NB ': 'N.ar',
    ' C1B': 'C.ar',
    ' C2B': 'C.ar',
    ' C3B': 'C.ar',
    ' C4B': 'C.ar',
    ' CMB': 'C.3',
    ' CAB': 'C.2',
    ' CBB': 'C.2',
    ' NC ': 'N.ar',
    ' C1C': 'C.ar',
    ' C2C': 'C.ar',
    ' C3C': 'C.ar',
    ' C4C': 'C.ar',
    ' CMC': 'C.3',
    ' CAC': 'C.2',
    ' CBC': 'C.2',
    ' ND ': 'N.ar',
    ' C1D': 'C.ar',
    ' C2D': 'C.ar',
    ' C3D': 'C.ar',
    ' C4D': 'C.ar',
    ' CMD': 'C.3',
    ' CAD': 'C.3',
    ' CBD': 'C.3',
    ' CGD': 'C.2',
    ' O1D': 'O.2',
    ' O2D': 'O.co2'
} # yapf: disable
#------------------------------------------------------------------------------#
CANVAS_MOL2_TYPE_NAME = {
    1: 'C.3',
    2: 'C.2',
    3: 'C.ar',
    4: 'C.1',
    33: 'C.cat',
    5: 'N.3',
    6: 'N.2',
    7: 'N.1',
    11: 'N.ar',
    28: 'N.am',
    19: 'N.pl3',
    31: 'N.4',
    8: 'O.3',
    9: 'O.2',
    32: 'O.co2',
    10: 'S.3',
    18: 'S.2',
    29: 'S.o',
    30: 'S.o2',
    12: 'P.3'
} # yapf: disable
#------------------------------------------------------------------------------#
[docs]class AtomTyper(object):
    '''
    Maps PDB residue/atom names onto SYBYL atom types.
    Uses ChmAtomTyperMol2 as fallback.
    '''
[docs]    def __init__(self):
        self.adaptor = canvas.ChmMmctAdaptor()
        self.mol2_typer = canvas.ChmAtomTyper(
            os.path.join(fileutils.get_mmshare_data_dir(), 'canvas',
                         'Mol2.typ')) 
    def __call__(self, st, atom_indices=None, logger=None):
        '''
        Assigns SYBYL atom types.
        :param st: Structure.
        :type st: `schrodinger.structure.Structure`
        :param atom_indices: Indices of the atoms to be considered.
        :type atom_indices: iterable over int
        :return: List of atom index-type pairs.
        :rtype: list(tuple(int, str or None))
        '''
        logger = common.ensure_logger(logger)
        if atom_indices is None:
            atom_indices = range(1, st.atom_total + 1)
        types = []
        all_found = True
        for i in atom_indices:
            atom = st.atom[i]
            try:
                t = RESIDUE_ATOM_TYPES[atom.pdbres][atom.pdbname]
            except KeyError:
                t = None
                all_found = False
                logger.debug('using fallback typer for atom %d (%s/%s)', i,
                             atom.pdbname, atom.pdbres)
            types.append((i, t))
        if all_found:
            return types
        assignments = self.mol2_typer.type(self.adaptor.create(st))
        for j in range(len(types)):
            i, t = types[j]
            if t is None:
                tc = assignments[i - 1]
                types[j] = (i, CANVAS_MOL2_TYPE_NAME.get(tc, None))
        return types 
#------------------------------------------------------------------------------#