import ln_scons

Import('env')
env = env.Clone()

AddOption('--only-manager', dest="only_manager", action="store_true", default=False, help="do only install ln_manager")
AddOption('--no-manager', dest="no_manager", action="store_true", default=False, help="do not install ln_manager")
AddOption('--no-python-api', dest="no_python_api", action="store_true", default=False, help="do not build & install LN client API for python")
AddOption('--no-python-base', dest="no_python_base", action="store_true", default=False, help="do not install python _base package")
AddOption('--no-python-lnrdb', dest="no_python_lnrdb", action="store_true", default=False, help="do not install python lnrdb package")
AddOption('--python-config', dest="PYTHON_CONFIG", type="string", metavar="EXECUTABLE", help="python-config executable to use. default is to use `$PYTHON-config`")
AddOption('--python-flags', dest="PYTHON_FLAGS", type="string", metavar="FLAGS", help="compiler/linker flags to use when building python extension. default is to use output of `python-config --cflags --ldflags`")
AddOption('--python-lib', dest="PYTHON_LIB", type="string", metavar="DIR", help="path under prefix where to install python packages to")
AddOption('--python-ext-dir', dest="PYTHON_EXT_DIR", type="string", metavar="DIR", help="arch-specific path component where to place _ln.so python extionsion")
AddOption('--python-shebang', dest="PYTHON_SHEBANG", type="string", metavar="COMMAND", help="shebang to use for executable python scripts, defaults to \"/usr/bin/env $PYTHON\"")
AddOption('--numpy-include', dest="NUMPY_INCLUDE", type="string", metavar="DIR", help="path where to find numpy/arrayobject.h, default is to use numpy.get_include()")
AddOption('--boost-python-lib', dest="BOOST_PYTHON_LIB", type="string", default=["boost_pythonXY", "boost_pythonX", "boost_python"], metavar="LIB", help="name of boost python library. default is to try `boost_python27` first, then `boost_python`")

if GetOption("help"):
    # early exit here not to execute config checks
    Return()

for opt in "PYTHON_CONFIG,PYTHON_LIB,PYTHON_EXT_DIR,PYTHON_SHEBANG,NUMPY_INCLUDE,PYTHON_FLAGS".split(","):
    env[opt] = GetOption(opt)

pycfg = None
def get_pycfg():
    global pycfg
    if pycfg is None:
        if not GetOption("crosscompiling"):
            pycfg = env.popen("$PYTHON %s" % File("./check_config.py"))
            pycfg = eval(pycfg)
        else:
            # use pkgconfig to find some parameters
            import os
            import subprocess
            pycfg = {}
            pycfg["python_major_minor"] = subprocess.check_output("pkg-config python3 --modversion", shell=True).decode("utf-8").strip().split(".")
            pycfg["ext_dir"] = "%s-%s-%s.%s" % ("linux", os.getenv("ARCH"), pycfg["python_major_minor"][0], pycfg["python_major_minor"][1])

            # search for numpy/arrayobject.h
            import os
            for root, dirs, files in os.walk(os.environ["PKG_CONFIG_SYSROOT_DIR"]):
                if "arrayobject.h" in files and "numpy" in root and "include" in root:
                    pycfg["numpy_include"] = os.path.dirname(root)
                    break
    return pycfg

if env["PYTHON_LIB"] is None:
    env["PYTHON_LIB"] = get_pycfg()["python_lib"]
if env["PYTHON_EXT_DIR"] is None:
    env["PYTHON_EXT_DIR"] = get_pycfg()["ext_dir"]
if env["PYTHON_SHEBANG"] is None:
    import os
    env["PYTHON_SHEBANG"] = "/usr/bin/env %s" % os.path.basename(env.subst("$PYTHON"))
if env["NUMPY_INCLUDE"] is None:
    env["NUMPY_INCLUDE"] = get_pycfg()["numpy_include"]

excludes = ("*.pyx", "*.pyc", "_*.so", "__pycache__")

# make sure $(dirname $PYTHON_LIB) below $PREFIX is included in `scons install`:
env.Alias("install-data", "$PREFIX/$PYTHON_LIB")
ln_scons.env_lines.append(
    "export PYTHONPATH=%s${PYTHONPATH:+:$PYTHONPATH}" % env.subst("$PREFIX/$PYTHON_LIB")
)

if not GetOption("no_manager"): # -> install ln_manager
    env.install_files("$PREFIX/$PYTHON_LIB", "links_and_nodes_manager", excludes=excludes + ("parser_tests", "ln_manager"))
    env.install_files("$PREFIX/$PYTHON_LIB", "links_and_nodes_manager_client", excludes=excludes)
    env.InstallData("$DATADIR/links_and_nodes_manager/includes", Glob("../../share/includes/*"))
    for what in "ln_manager", "lnmc", "ln_notebook", "ln_topic_scope":
        env.replace_shebang(what + "_entry", "links_and_nodes_manager/" + what, env["PYTHON_SHEBANG"])
        env.InstallAs("$PREFIX/bin/" + what, what + "_entry")

if not GetOption("only_manager") and not GetOption("no_python_base"): # -> install LN base package
    env.install_files("$PREFIX/$PYTHON_LIB", "links_and_nodes_base", excludes=excludes + ("parser_tests", ))
    env.install_files("$PREFIX/$PYTHON_LIB", "pyutils", excludes=excludes + ("*.h", "*.cpp"))
    env.replace_shebang("ln_generate_entry", "links_and_nodes_base/ln_generate", env["PYTHON_SHEBANG"])
    env.InstallAs("$PREFIX/bin/ln_generate", "ln_generate_entry")
    env.install_mds(Dir("#share/message_definitions"), excludes=("tests/*", ), target="links_and_nodes")
    
if not GetOption("only_manager") and not GetOption("no_python_lnrdb"): # -> install lnrdb python tools
    env.install_files("$PREFIX/$PYTHON_LIB", "lnrdb", excludes=excludes + ("conanfile.py", ))
    
if not GetOption("only_manager") and not GetOption("no_python_api") and not GetOption("clean"): # -> build & install LN client API for python
    pymajor, pyminor = get_pycfg()["python_major_minor"]
    import os
    if env["PYTHON_FLAGS"] is None:
        # try to use python-config to get those flags!
        if env["PYTHON_CONFIG"] is None:
            env["PYTHON_CONFIG"] = env["PYTHON"] + "-config"
        print("using python-config: %r" % env["PYTHON_CONFIG"])
        if not env["PYTHON_CONFIG"].strip():
            print("Error: can't find python-config program!")
            print("on debian install package python-dev or try to use the --python-config=XY option.")
            Exit(1)
        # hack to allow /opt/python/osl42-x86_64/python2/stable/1.2.0/bin/python2-config to find correct python include dir
        env["LD_LIBRARY_PATH"] = os.getenv("LD_LIBRARY_PATH", "")
        env["PYTHON_FLAGS"] = env.popen("$PYTHON_CONFIG --cflags --ldflags") # get flags to link to python
        add_flags = "--embed" if pymajor > 3 or (pymajor == 3 and pyminor >= 8) else ""
        env["PYTHON_FLAGS_BOOST"] = env.popen("$PYTHON_CONFIG --cflags --ldflags " + add_flags) # get -lpythonx.x flag for finding boost
    else:
        env["PYTHON_FLAGS_BOOST"] = env["PYTHON_FLAGS"]
    
    env.MergeFlags(env["PYTHON_FLAGS"], unique=1)

    # remove this C-only flag for our c++ compile to silence g++ warning
    env["CCFLAGS"] = list(filter(lambda f: f != "-Wstrict-prototypes", env["CCFLAGS"]))

    # verify that this stuff works
    conf = env.CloneConfigureEnv().Configure()
    if not conf.CheckHeader('Python.h', '<>'):
        print("Error: can't find Python.h header using these flags: %s" % env["PYTHON_FLAGS"])
        print("install python headers (package libpython-dev on debian)")
        Exit(1)
    conf.Finish()
    
    # build & install python binding
    # WOW! -- einfach nur WOW!
    #conf.CheckLib(["boost_python27", "boost_python"], autoadd=1)
    link_check_env = env.CloneConfigureEnv()
    link_check_env.MergeFlags(env["PYTHON_FLAGS_BOOST"], unique=1)
    conf = link_check_env.Configure()

    options = GetOption("BOOST_PYTHON_LIB")
    if not isinstance(options, list):
        options = [options]
    for alt in options:
        if alt == "boost_pythonX":
            alt = "boost_python%s" % pymajor
        if alt == "boost_pythonXY":
            alt = "boost_python%s%s" % (pymajor, pyminor)
        if conf.CheckLib(alt, autoadd=0):
            env.Append(LIBS=[alt])
            break
    else:
        print("Error: missing libboost_python! maybe try to use the --boost-python-lib=XY option.")
        Exit(1)
    conf.Finish()
    
    common_compiler_flags = [ "-Wall" ]
    env.Append(
        CPPPATH=env["NUMPY_INCLUDE"],
        CFLAGS=common_compiler_flags,
        CXXFLAGS=common_compiler_flags + [env.set_stdflag("gnu++11")],
        LINKFLAGS=["-Wl,-rpath,'$$ORIGIN/../libln'"]
    )

    ext_dir = env["PYTHON_EXT_DIR"]
    env["SHLIBPREFIX"] = ''
    env["SHOBJPREFIX"] = ext_dir
    _ln_so = env.SharedLibrary(os.path.join(ext_dir, "_ln"), source=[ "links_and_nodes/_ln.cpp" ])

    # place symlink in source-dir to be able to run from there!
    symlink_dst = str(Dir("links_and_nodes").srcnode()) + "/src-" + ext_dir
    symlink_src = Dir(ext_dir).get_abspath()
    if not os.path.lexists(symlink_dst):
        kwargs = dict()
        import sys
        if sys.version_info[0] >= 3:
            kwargs["target_is_directory"] = True
        os.symlink(symlink_src, symlink_dst, **kwargs)
    excludes += (ext_dir, "src-*", "conanfile.py")
    env.Install("$PREFIX/$PYTHON_LIB/links_and_nodes/%s" % ext_dir, _ln_so)
    env.install_files("$PREFIX/$PYTHON_LIB", "links_and_nodes", excludes=excludes)
    env.replace_shebang("fs_sync_entry", "#ln_runtime/file_services/fs_sync", env["PYTHON_SHEBANG"])
    env.InstallAs("$PREFIX/bin/fs_sync", "fs_sync_entry") # strangly this installs into libln/install-sandbox/prefix/bin/
