#
#  Copyright (C) 2025 Greg Landrum
#         All Rights Reserved
#
#  This file is part of the RDKit.
#  The contents are covered by the terms of the BSD license
#  which is included in the file license.txt, found at the root
#  of the RDKit source tree.
#

#
import unittest

from rdkit import Chem


class TestCase(unittest.TestCase):

  def setUp(self):
    pass

  def testExtraAtomMatch(self):
    """Test setting extra atom matching functions """
    mol = Chem.MolFromSmiles('CCCC')
    mol.GetAtomWithIdx(1).SetIntProp('foo', 1)
    mol.GetAtomWithIdx(2).SetIntProp('foo', 2)
    patt = Chem.MolFromSmiles('CC')
    patt.GetAtomWithIdx(0).SetIntProp('bar', 2)
    patt.GetAtomWithIdx(1).SetIntProp('bar', 1)

    def atomCheck(qatom, ratom):
      if not qatom.HasProp('bar') or not ratom.HasProp('foo'):
        return False
      return qatom.GetIntProp('bar') == ratom.GetIntProp('foo')

    matches = mol.GetSubstructMatches(patt)
    self.assertEqual(len(matches), 3)

    params = Chem.SubstructMatchParameters()
    params.setExtraAtomCheckFunc(atomCheck)

    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (2, 1))

    # override default check
    patt = Chem.MolFromSmiles('CO')
    patt.GetAtomWithIdx(0).SetIntProp('bar', 2)
    patt.GetAtomWithIdx(1).SetIntProp('bar', 1)

    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 0)

    params.extraAtomCheckOverridesDefaultCheck = True
    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (2, 1))

  def testExtraBondMatch(self):
    """Test setting extra bond matching functions """
    mol = Chem.MolFromSmiles('CCCC')
    mol.GetBondWithIdx(1).SetIntProp('foo', 1)
    patt = Chem.MolFromSmiles('CC')
    patt.GetBondWithIdx(0).SetIntProp('bar', 1)

    def bondCheck(qbond, rbond):
      if not qbond.HasProp('bar') or not rbond.HasProp('foo'):
        return False
      return qbond.GetIntProp('bar') == rbond.GetIntProp('foo')

    matches = mol.GetSubstructMatches(patt)
    self.assertEqual(len(matches), 3)

    params = Chem.SubstructMatchParameters()
    params.setExtraBondCheckFunc(bondCheck)

    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (1, 2))

    # override default check
    patt = Chem.MolFromSmiles('C=C')
    patt.GetBondWithIdx(0).SetIntProp('bar', 1)

    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 0)

    params.extraBondCheckOverridesDefaultCheck = True
    matches = mol.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (1, 2))

  def testCoordsFunctor(self):
    m = Chem.MolFromSmiles('CCCC |(0,0,0;1,0,0;2,0,0;3,0,0)|')
    patt = Chem.MolFromSmiles('CC |(3,0,0.1;2,0,0)|')

    params = Chem.SubstructMatchParameters()
    coordMatcher = Chem.AtomCoordsMatcher(tol=.11)
    params.setExtraAtomCheckFunc(coordMatcher)
    matches = m.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (3, 2))

    # lifetime management 1:
    coordMatcher = None
    matches = m.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (3, 2))

    # lifetime management 2:
    params.setExtraAtomCheckFunc(Chem.AtomCoordsMatcher(tol=.11))
    matches = m.GetSubstructMatches(patt, params)
    self.assertEqual(len(matches), 1)
    self.assertEqual(matches[0], (3, 2))


if __name__ == '__main__':
  unittest.main()
