###  Tools
__all__ = ["Dtool_ObjectToDict", "Dtool_funcToMethod", "Dtool_PreloadDLL"]

import imp, sys, os

# The following code exists to work around a problem that exists
# with Python 2.5 or greater.

# Specifically, Python 2.5 is designed to import files named *.pyd
# only; it will not import files named *.dll (or *.so).  We work
# around this problem by explicitly preloading all of the dll's we
# expect to need.

dll_suffix = ''
if sys.platform == "win32":
    # On Windows, dynamic libraries end in ".dll".
    dll_ext = '.dll'
    module_ext = '.pyd'

    # We allow the caller to preload dll_suffix into the sys module.
    dll_suffix = getattr(sys, 'dll_suffix', None)

    if dll_suffix is None:
        # Otherwise, we try to determine it from the executable name:
        # python_d.exe implies _d across the board.
        dll_suffix = ''
        if sys.executable.endswith('_d.exe'):
            dll_suffix = '_d'
            
elif sys.platform == "darwin":
    # On OSX, the dynamic libraries usually end in .dylib, but
    # sometimes we need .so.
    try:
        from direct.extensions_native.extensions_darwin import dll_ext
    except ImportError:
        dll_ext = '.dylib'
    module_ext = '.so'
else:
    # On most other UNIX systems (including linux), .so is used.
    dll_ext = '.so'
    module_ext = '.so'

if sys.platform == "win32":
    # On Windows, we must furthermore ensure that the PATH is modified
    # to locate all of the DLL files.

    # First, search for the directory that contains all of our compiled
    # modules.
    target = None
    filename = "libpandaexpress%s%s" % (dll_suffix, dll_ext)
    for dir in sys.path + [sys.prefix]:
        lib = os.path.join(dir, filename)
        if (os.path.exists(lib)):
            target = dir
    if target == None:
        message = "Cannot find %s" % (filename)
        raise ImportError(message)

    # And add that directory to the system path.
    path = os.environ["PATH"]
    if not path.startswith(target + ";"):
        os.environ["PATH"] = target + ";" + path

def Dtool_FindModule(module):
    # Finds a .pyd module on the Python path.
    filename = module.replace('.', os.path.sep) + module_ext
    for dir in sys.path:
        lib = os.path.join(dir, filename)
        if (os.path.exists(lib)):
            return lib

    return None

def Dtool_PreloadDLL(module):
    if module in sys.modules:
        return

    # First find it as a .pyd module on the Python path.
    if Dtool_FindModule(module):
        # OK, we should have no problem importing it as is.
        return

    # Nope, we'll need to search for a dynamic lib and preload it.
    # Search for the appropriate directory.
    target = None
    filename = module.replace('.', os.path.sep) + dll_suffix + dll_ext
    for dir in sys.path + [sys.prefix]:
        lib = os.path.join(dir, filename)
        if (os.path.exists(lib)):
            target = dir
            break

    if target is None:
        message = "DLL loader cannot find %s." % (module)
        raise ImportError(message)

    # Now import the file explicitly.
    pathname = os.path.join(target, filename)
    imp.load_dynamic(module, pathname)    

# Nowadays, we can compile libpandaexpress with libpanda into a
# .pyd file called panda3d/core.pyd which can be imported without
# any difficulty.  Let's see if this is the case.
if Dtool_FindModule("panda3d.core"):
    from panda3d.core import *
else:
    Dtool_PreloadDLL("libpandaexpress")
    from libpandaexpress import *

def Dtool_ObjectToDict(cls, name, obj):
    cls.DtoolClassDict[name] = obj;

def Dtool_funcToMethod(func, cls, method_name=None):
    """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method.
    The new method is accessible to any instance immediately."""
    if sys.version_info < (3, 0):
        func.im_class = cls
    func.im_func = func
    func.im_self = None
    if not method_name:
        method_name = func.__name__
    cls.DtoolClassDict[method_name] = func;