#!/usr/bin/env python
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.

import sys

from openeye import oechem
from openeye import oedocking


# @ <SNIPPET-POSEBEST-HELPER>
# Return the index of the best receptor for posing ligand
def BestReceptorIndex(ligand, receptors):
    best_idx = len(receptors) + 1
    best_probability = 0.0

    for receptor_index, receptor in enumerate(receptors):
        probability = oedocking.OEGetEstimatedPositProbability(ligand, receptor)
        if probability > best_probability:
            best_probability, best_idx = probability, receptor_index

    return best_idx
# @ </SNIPPET-POSEBEST-HELPER>


def main(argv=[__name__]):
    itf = oechem.OEInterface(InterfaceData)
    if not oechem.OEParseCommandLine(itf, argv):
        return 1

    # @ <SNIPPET-POSEBEST-MOLECULES-READRECEPTORS>
    receptors = []
    for receptor_filename in itf.GetStringList("-receptors"):
        receptor = oechem.OEGraphMol()
        if not oedocking.OEReadReceptorFile(receptor, receptor_filename):
            oechem.OEThrow.Fatal("Unable to read receptor from %s" %
                                 receptor_filename)
        receptors.append(receptor)
    # @ </SNIPPET-POSEBEST-MOLECULES-READRECEPTORS>

    # @ <SNIPPET-POSEBEST-MOLECULES-SETUP>
    poser = oedocking.OEPosit()
    # @ </SNIPPET-POSEBEST-MOLECULES-SETUP>

    # Identify the best receptors
    imstr = oechem.oemolistream()
    if not imstr.open(itf.GetString("-in")):
        oechem.OEThrow.Fatal("Could not open %s for reading", itf.GetString("-in"))
    mcmol = oechem.OEMol()
    ligand_number = 0
    bestReceptorIdx = {}
    while oechem.OEReadMolecule(imstr, mcmol):
        bestReceptorIdx[ligand_number] = BestReceptorIndex(mcmol, receptors)
        ligand_number += 1
    imstr.close()

    # Loop through all the receptors and pose molecules
    for receptor_idx, receptor in enumerate(receptors):
        # write out a new output file for each receptor
        #  <prefix>_#.oeb.gz

        omstr = oechem.oemolostream("%s_%s.oeb" % (itf.GetString("-prefix"),
                                    receptor_idx))
        poser.Initialize(receptor)

        imstr = oechem.oemolistream()
        if not imstr.open(itf.GetString("-in")):
            oechem.OEThrow.Fatal("Could not open %s for reading", itf.GetString("-in"))

        ligand_number = 0
        # @ <SNIPPET-POSEBEST-CHOOSEBEST>
        while oechem.OEReadMolecule(imstr, mcmol):
            #  is the current receptor the best one?
            if receptor_idx == bestReceptorIdx[ligand_number]:
                oechem.OEThrow.Info("Posing ligand %s(%d) to receptor %s(%d)"
                                    % (mcmol.GetTitle(), ligand_number,
                                       receptor.GetTitle(), receptor_idx))

                posedMol = oechem.OEGraphMol()
                poser.DockMultiConformerMolecule(posedMol, mcmol)

                oedocking.OESetSDScore(posedMol, poser, poser.GetName())
                oechem.OEWriteMolecule(omstr, posedMol)
            ligand_number += 1
        # @ </SNIPPET-POSEBEST-CHOOSEBEST>

    return 0


InterfaceData = """
# Begin the definition of the -receptor command line parameter.
!PARAMETER -receptors

  # allows the use of -rec on the command as a shortcut for -receptors
  !ALIAS -rec

  # Parameter is a of type string
  !TYPE string

  # parameter can support multiple receptors ala
  #  -receptors *.oeb.gz
  !LIST true

  # Tells the OEParseCommandLine function to throw an error if this
  # parameter isn't specified on the command line
  !REQUIRED true

  # Specifies that only strings ending in .oeb or .oeb.gz are legal
  # settings for this parameter (OEParseCommandLine will throw an error)
  !LEGAL_VALUE *.oeb
  !LEGAL_VALUE *.oeb.gz

  # Description of the parameter (accessible by the users via --help command)
  !BRIEF A receptor file the molecules pass to the -in flag will be posed to

# End the definition of -receptor parameter
!END


# Begin definition of -in command line parameter
!PARAMETER -in

  # Parameter is of type string
  !TYPE string

  # Parameter must be specified on the command line or OEParseCommandLine
  # function will throw an error.
  !REQUIRED true

  # Description of the parameter (accessible by the users via --help command)
  !BRIEF Multiconformer file of molecules to be posed.

# End of the definition of -in
!END


# Begin definition of -prefix command line parameter
!PARAMETER -prefix

  # Parameter is of type string
  !TYPE string

  # Parameter must be specified on the command line or OEParseCommandLine
  # function will throw an error.
  !REQUIRED true

  # Description of the parameter (accessible by the users via --help command)
  !BRIEF Posed molecules will be written to this file using this prefix <prefix>_<receptor#>.oeb

# End of the definition of -prefix
!END
"""

if __name__ == "__main__":
    sys.exit(main(sys.argv))
