#  Copyright (C) 2017 The authors of Py-ChemShell
#
#  This file is part of Py-ChemShell.
#
#  Py-ChemShell is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  Py-ChemShell is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with Py-ChemShell.  If not, see
#  <http://www.gnu.org/licenses/>.

import ctypes, os.path
from chemsh import CHEMSH_ARCH

# load Fortran ChemShell library
#soname     = os.path.dirname(__file__) + '/../lib/libchemsh.so'
# use cross-platform function os.path.join()
#soname = os.path.join(os.path.dirname(__file__), '..', 'lib', CHEMSH_ARCH, 'libchemsh.so')

# use this platform-independent way to join paths
#libchemsh = ctypes.CDLL(soname)



def getClasses(package, pkg_path=''):
    ''''''

    from inspect   import getmembers, isclass, ismodule
    from importlib import import_module
    from pkgutil   import walk_packages

    # YL 26/02/2021: we shouldn't raise WARNING when scanning the package's classes;
    #                do not use `from chemsh import CHEMSH_DEBUG` otherwise the value
    #                CHEMSH_DEBUG value isn't really saved in the module object `chemsh`
    import chemsh

    classes = {}

    # save the value
    debug, chemsh.CHEMSH_DEBUG = chemsh.CHEMSH_DEBUG, -1

    def __updateClasses(__classes, __pkgname):
        ''''''

        # ignore those can't be imported
        try:
            mod = import_module(__pkgname)
        except:
            mod = None

        # get a list of ChemShell-defined classes
        try:
            l = [ m[0] for m in getmembers(mod, isclass) if m[1].__module__ == __pkgname ]
        except:
            l = []

        for i in l:
            # in ChemShell all classes definitions should start with a capital letter (could be underscored)
            if i[0].isupper():
                __classes[i] = pkgname

    #    
    if not ismodule(package):
        return classes

    # YL 06/10/2020: added prefix to prevent global packages being searched
    for _loader, pkgname, is_pkg in walk_packages(path=package.__path__, prefix=package.__name__ + '.'):

        if is_pkg:
            __updateClasses(classes, pkgname)
            # recursively search in subpackages
            classes.update(getClasses(import_module(pkgname), pkg_path=pkg_path))
        else:
            __updateClasses(classes, pkgname)

    # restore the value
    chemsh.CHEMSH_DEBUG = debug

    return classes


def importClasses(package, pkg_path=''):
    ''''''

    from importlib import import_module

    classes = getClasses(package, pkg_path=pkg_path)

    for key, val in classes.items():

        cls = getattr(import_module(val), key)

        setattr(package, key, cls)






