#!/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.

#############################################################################
# Apply a transformation
#############################################################################
import sys
from openeye import oechem


def main(argv=[__name__]):
    itf = oechem.OEInterface(InterfaceData, argv)

    opts = oechem.OEUniMolecularRxnOptions()

    opts.SetStrictSmirks(itf.GetBool("-strict"))
    opts.SetClearCoordinates(itf.GetBool("-clearcoords"))
    opts.SetValidateKekule(itf.GetBool("-validkek"))
    opts.SetMaxMatches(itf.GetInt("-max"))

    altered = itf.GetString("-alteredtag")
    opts.SetAlteredTag("")
    if altered:
        opts.SetAlteredTag(altered)

    fixval = itf.GetString("-fixval")
    if fixval.upper() == "EXPLICIT" or fixval.upper() == "NONE":
        opts.SetFixValence(oechem.OEUniMolecularRxnFixValence_Explicit)
    elif fixval.upper() == "ALTERED":
        opts.SetFixValence(oechem.OEUniMolecularRxnFixValence_Altered)
    elif fixval.upper() == "ALL":
        opts.SetFixValence(oechem.OEUniMolecularRxnFixValence_All)
    else:
        oechem.Error("Unknown fix valence request: {}".format(fixval))

    xform = itf.GetString("-smirks")
    xformname = None
    if " " in xform:
        xform, xformname = xform.split(" ")[:2]

    qrxn = oechem.OEQMol()
    if not oechem.OEParseSmirks(qrxn, xform):
        oechem.Fatal("SMIRKS parse error: {}".format(xform))

    ifs = oechem.oemolistream()
    if not ifs.open(itf.GetString("-in")):
        oechem.OEThrow.Fatal(
            "Unable to open {} for reading".format(itf.GetString("-in"))
        )

    ofs = oechem.oemolostream()
    if not ofs.open(itf.GetString("-out")):
        oechem.OEThrow.Fatal(
            "Unable to open {} for writing".format(itf.GetString("-out"))
        )

    outfails = None
    if itf.HasString("-noxform"):
        print('noform=[{}]'.format(itf.GetString("-noxform")))
        outfails = oechem.oemolostream()
        if not outfails.open(itf.GetString("-noxform")):
            oechem.OEThrow.Fatal(
                "Unable to open failure file {} for writing".format(itf.GetString("-noxform"))
            )

    all2output = itf.GetBool("-passfail")
    asrxn = itf.GetBool("-asrxn")

    outxfmmol = oechem.OEGraphMol()
    for mol in ifs.GetOEGraphMols():
        title = mol.GetTitle()
        insmi = oechem.OEMolToSmiles(mol)

        nxforms = 0
        for xfmmol in oechem.OEGetUniMolecularRxnIter(mol, qrxn, opts):
            nxforms += 1
            if not asrxn:
                if xformname:
                    xfmmol.SetTitle("{}:{}({})".format(nxforms, xformname, mol.GetTitle()))
                if (
                    oechem.OEWriteMolecule(ofs, xfmmol)
                    != oechem.OEWriteMolReturnCode_Success
                ):
                    oechem.Fatal(
                        "Error writing molecule: {}".format(oechem.OEMolToSmiles(xfmmol))
                    )
            else:
                oechem.OESmilesToMol(
                    outxfmmol, "{}>>{}".format(insmi, oechem.OEMolToSmiles(xfmmol))
                )
                if xformname:
                    outxfmmol.SetTitle("{}:{}({})".format(nxforms, xformname, title))
                else:
                    outxfmmol.SetTitle(title)
                if (
                    oechem.OEWriteMolecule(ofs, outxfmmol)
                    != oechem.OEWriteMolReturnCode_Success
                ):
                    oechem.Fatal(
                        "Error writing molecule: {}".format(
                            oechem.OEMolToSmiles(outxfmmol)
                        )
                    )

        if not nxforms:
            if all2output:
                if (
                    oechem.OEWriteMolecule(ofs, mol)
                    != oechem.OEWriteMolReturnCode_Success
                ):
                    oechem.Fatal(
                        "Error writing untransformed molecule: {}".format(oechem.OEMolToSmiles(xfmmol))
                    )
            elif outfails:
                if (
                    oechem.OEWriteMolecule(outfails, mol)
                    != oechem.OEWriteMolReturnCode_Success
                ):
                    oechem.Fatal(
                        "Error writing untransformed molecule: {}".format(oechem.OEMolToSmiles(mol))
                    )
            
    return 0


InterfaceData = """
!BRIEF -smirks SMIRKS -in <input> -out <output>
    !CATEGORY I/O
        !PARAMETER -smirks 1
          !ALIAS -xform
          !TYPE string
          !REQUIRED true
          !BRIEF Transformation SMIRKS
          !KEYLESS 1
        !END
        !PARAMETER -in 2
          !ALIAS -i
          !TYPE string
          !REQUIRED true
          !BRIEF Input file name
          !KEYLESS 2
        !END
        !PARAMETER -out 3
          !ALIAS -o
          !ALIAS -success
          !TYPE string
          !REQUIRED true
          !BRIEF Output file name
          !KEYLESS 3
        !END
        !PARAMETER -noxform 4
          !ALIAS -fails
          !ALIAS -failures
          !TYPE string
          !REQUIRED false
          !BRIEF Output file name for untransformed structures
        !END
    !END
    !CATEGORY Options
        !PARAMETER -strict 1
          !ALIAS -strictsmirks
          !TYPE bool
          !REQUIRED false
          !DEFAULT true
          !BRIEF  requested strict flag which controls the interpretation of the transformation SMIRKS (true:Daylight convention, false:OpenEye convention)
        !END
        !PARAMETER -clearcoords 2
          !TYPE bool
          !REQUIRED false
          !DEFAULT true
          !BRIEF whether to clear coordinates for transformed products
        !END
        !PARAMETER -validkek 3
          !ALIAS -validkekule
          !TYPE bool
          !REQUIRED false
          !DEFAULT true
          !BRIEF whether the transformation validates the Kekule form of the transformed products
        !END
        !PARAMETER -fixval 4
          !TYPE string
          !REQUIRED false
          !DEFAULT Explicit
          !BRIEF type of valence correction to apply to the transformed products: Explicit(None), Altered, All
        !END
        !PARAMETER -max 5
          !ALIAS -maxxforms
          !TYPE int
          !REQUIRED false
          !DEFAULT 10
          !BRIEF maximum number of transformation to apply to each processed molecule
        !END
        !PARAMETER -alteredtag 6
          !TYPE string
          !REQUIRED false
          !DEFAULT None
          !BRIEF A generic data tag to mark altered atom information from transformed products
        !END
        !PARAMETER -passfail 7
          !TYPE bool
          !REQUIRED false
          !DEFAULT false
          !BRIEF If true, include untransformed structures in -out
        !END
        !PARAMETER -asrxn 8
          !TYPE bool
          !REQUIRED false
          !DEFAULT false
          !BRIEF If true, output the transformation as a reaction
        !END
    !END
!END
"""

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