# -*-python-*-
#-------------------------------------------------------------------------------
#
#       OpenAlea.SConsX: SCons extension package for building platform
#                        independant packages.
#
#       Copyright 2005-2007 INRIA - CIRAD - INRA
#
#       File author(s):
#               Christophe Pradal <christophe.prada@cirad.fr>
#               Pierre Barbier de Reuille <pierre.barbier@sophia.inria.fr>
#               Samuel Dufour-Kowalski <samuel.dufour@sophia.inria.fr>
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
#       OpenAlea WebSite : http://openalea.gforge.inria.fr
#
#--------------------------------------------------------------------------------
"""This module add some facilities to simplify the SConscript files to
the minimum.  It contains wrapper functions that extend the SCons
environment and abstract the operating system.

Each function defines or populate global aliases like build or install.
"""

__license__ = "Cecill-C"
__revision__ = "$Id$"

import os, sys

#from path import path
from SCons.Script.SConscript import SConsEnvironment, DefaultEnvironmentCall
import SCons.Builder
import SCons.Action
import SCons.Node.FS

Alias = DefaultEnvironmentCall("Alias")


def ALEALibrary(env, target, source, *args, **kwds):

    """
    Build static or dynamic library depending on user flags.
    Install the build library and associated files in specific directories.
    Define 'build' and 'install' target.
    """
    _target = env.subst("$build_libdir/%s"%target)
    if env.get("static", False):
        lib = env.StaticLibrary(_target, source, *args, **kwds)
    else:
        if (env['compiler'] == 'msvc') and ('8.0' in env['MSVC_VERSION']):
            kwds['SHLINKCOM'] = [env['SHLINKCOM'],
            'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
        lib = env.SharedLibrary(_target, source, *args, **kwds)

    def select_dll(lib):
        # On windows, we need to separate dll and lib
        try:
            # Visual style
            dll, lib, exp = lib
        except:
            # mingw style
            dll, lib = lib
        return dll, lib

    # Building
    bld_lib = lib
    if os.name != 'posix' and not env.get("static", False) :
        # For windows, we should still move the dll and lib in separate directory.
        dll, lib = select_dll(lib)
        dll = env.Install("$build_bindir", dll)
        Alias("build_lib", dll)
        Alias("build", dll)
        bld_lib = dll + [lib]

    Alias("build_lib", lib)
    Alias("build", lib)

    # Installing
    inst_lib =  []
    if os.name != 'posix' and not env.get("static", False):
        # On windows, we need to install the dll.
        if env.subst("$build_bindir") != env.subst("$bindir"):
            dll = env.Install("$bindir", dll)
            inst_lib += dll
        # else we reuse the already installed dll

        Alias("install_lib", dll)
        Alias("install", dll)

    if env.subst("$build_libdir") != env.subst("$libdir"):
        # We should install the lib in libdir
        lib = env.Install("$libdir", lib)
        inst_lib += lib
    # else we reuse the already installed lib

    Alias("install_lib", lib)
    Alias("install", lib)

    return (bld_lib, inst_lib)

def ALEAIncludes(env, target, includes, *args, **kwds):
    """
    Install the headers in the directory .../include/mypackage
    Define 'build' and 'install' target.
    """
    inc = env.Install("$build_includedir/%s" % (target,), includes, *args, **kwds)
    env.Alias("build_lib", inc)
    env.Alias("build", inc)
    if env.subst("$build_includedir") == env.subst("$includedir"):
        inst_inc =  []
        # In this case, this target should simply be build for install mode
        Alias("install_lib", inc)
        Alias("install", inc)
    else:
        inst_inc = env.Install("$includedir/%s" % (target,), includes, *args, **kwds)
        Alias("install_lib", inst_inc)
        Alias("install", inst_inc)
    return (inc, inst_inc)


def ALEAProgram(env, target, source, *args, **kwds):
    """
    Build a program and install it in local and system directories.
    """
    bin = env.Program("$build_bindir/%s" % (target,), source, *args, **kwds)
    Alias("build", bin)
    Alias("build_lib", bin)
    if env.subst("$build_bindir") == env.subst("$bindir"):
        inst_bin =  []
        # In this case, this target should simply be build for install mode
        Alias("install_lib", bin)
        Alias("install", bin)
    else:
        inst_bin = env.Install("$bindir", bin)
        Alias("install_lib", inst_bin)
        Alias("install", inst_bin)
    return (bin, inst_bin)

def ALEAWrapper(env, python_dir, target, source, *args, **kwds):
    """
   Build a python wrapper and install it in a python package.
    """
    real_target = "%s/%s" % (str(env.Dir(python_dir).srcnode()), target)

    if os.name == 'nt':
        kwds['SHLIBSUFFIX'] = '.pyd'
    else:
        kwds['SHLIBSUFFIX'] = '.so'

    if (env['compiler'] == 'msvc') and ('8.0' in env['MSVC_VERSION']):
        kwds['SHLINKCOM'] = [env['SHLINKCOM'],
        'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']

    if os.name == 'nt':
    # Fix bug with Scons 0.97, Solved in newer versions.
        wrap = env.SharedLibrary(real_target, source,
                           SHLIBPREFIX='',
                           *args, **kwds)
    elif sys.platform == 'darwin':
        wrap = env.LoadableModule(real_target, source,
                           SHLIBPREFIX='',
                           LDMODULESUFFIX='.so',
                           FRAMEWORKSFLAGS = \
                            '-flat_namespace -undefined suppress',
                           *args, **kwds)
    else:
        wrap = env.LoadableModule(real_target, source,
                           SHLIBPREFIX='',
                           *args, **kwds)
    Alias("build_wrapper", wrap)
    Alias("build", wrap)
    # This target should simply be build for install mode
    Alias("install", wrap)
    return wrap

## def ALEAPython(env, python_dir, depends = [], *args, **kwds):
##   """
##   Install recursively python package and data.
##   """
##   p = env.Dir(python_dir).srcnode()
##   base = "$pythondir/$package_name"
##   base_py = len(path(python_dir).abspath())
##   fi = []
##   for d in depends:
##     real_d = "%s/%s" % (str(env.Dir(python_dir).srcnode()), str(d))
##     fi.append(env.Install(base, d))
##   for f in p.walk():
##     fi.append(env.Install("%s/%s" % (base, f.parent[base_py:]), str(f)))
##   Alias("install", fi)
##   return fi

def ALEAGlob(env, pattern, dir = '.'):
    import os, fnmatch, glob
    files = []
    dirs = []
    is_multidirs = False
    if '*' in dir:
        here = env.Dir('.').srcnode().abspath
        d = os.path.join(here, dir)
        dirs = list(filter(os.path.isdir, glob.glob(d)))
        is_multidirs = True
    else:
        here = env.Dir(dir).srcnode().abspath
        dirs = [here]

    for d in dirs:
        for ufile in os.listdir(d):
            if fnmatch.fnmatch(ufile, pattern) :
                if is_multidirs:
                    files.append(os.path.join(os.path.basename(d), ufile))
                else:
                    files.append(os.path.join(dir, ufile))
    return files

def ALEAGlobDir(env, pattern, dir='.'):
    import os, glob

    here = env.Dir(dir).srcnode().abspath
    d = os.path.join(here, pattern)
    dirs = list(filter(os.path.isdir, glob.glob(d)))
    dirs = [d.replace(here, dir) for d in dirs]

    return dirs

SConsEnvironment.ALEALibrary = ALEALibrary
SConsEnvironment.ALEAIncludes = ALEAIncludes
SConsEnvironment.ALEAProgram = ALEAProgram
SConsEnvironment.ALEAWrapper = ALEAWrapper
SConsEnvironment.ALEAGlob = ALEAGlob
SConsEnvironment.ALEAGlobDir = ALEAGlobDir
##SConsEnvironment.ALEAPython = ALEAPython

