#
# author: Achim Gaedke, Pierre Schnizer
# created: May 2001
# modified: Sep 2017
# file: pygsl_lite/gsl_dist/gsl_extension.py
# $Id$
#
# module for gsl extensions compilation

from setuptools import setup, Extension
from distutils.errors import DistutilsModuleError, DistutilsExecError
from distutils.dep_util import newer_group

import os
import os.path
import re
import string
import types
from sys import argv, version_info

from gsl_Location import gsl_Location

try:
    from array_includes import array_include_dirs
except ImportError:
    from pygsl_lite.gsl_dist.array_includes import array_include_dirs


# def check_dependencies(sources, depends):
# 	"""Check if any of the dependencies is newer than the src
#
# 	It assumes that the dependencies are in the same directory as the
# 	src file
#
# 	Returns:
# 	     the deps if they are newer than the src file, None if not
# 	"""
# 	is_old = True
# 	for src in sources:
# 		t_dir = os.path.dirname(src)
# 		check_deps = map(lambda x: os.path.join(t_dir, x), depends)
# 		is_old = newer_group(check_deps, src)
# 		print("src %s is old %s" % (src, is_old))
# 		if is_old == True:
# 			break
#
# 	if is_old == False:
# 		return None
#
# 	return depends


class gsl_Extension(Extension):
    """
    for gsl needs
    """

    def __init__(
        self,
        name,
        sources,
        include_dirs=None,
        define_macros=None,
        undef_macros=None,
        library_dirs=None,
        libraries=None,
        runtime_library_dirs=None,
        extra_objects=None,
        extra_compile_args=None,
        extra_link_args=None,
        export_symbols=None,
        gsl_prefix=None,
        gsl_min_version=None,
        python_min_version=None,
        depends=None,
        **kws,
    ):

        # get real prefix
        self.gsl_prefix = self.get_gsl_prefix()

        extra_compile_args = (extra_compile_args or []) + [
            "-Werror=incompatible-pointer-types"
        ]

        gsl_major_version, gsl_minor_version = self.get_gsl_version()
        # check gsl version
        if gsl_min_version is not None and not self.check_gsl_version(gsl_min_version):
            raise DistutilsExecError(
                "min gsl version %s required" % repr(gsl_min_version)
            )

        # check python version
        if python_min_version is not None and not self.check_python_version(
            python_min_version
        ):
            raise DistutilsExecError(
                "min python version %s required" % repr(python_min_version)
            )

        # prepend include directory
        if include_dirs is None:
            include_dirs = []
        include_dirs.append("Include")
        include_dirs.append(".")
        include_dirs = gsl_Location.get_gsl_include_dirs() + include_dirs
        include_dirs = include_dirs + array_include_dirs

        # prepend library directory
        if library_dirs is None:
            library_dirs = []
        library_dirs = library_dirs + gsl_Location.get_gsl_library_dirs()

        # Testing linking to non standard location if standard location is available
        # runtime_library_dirs = gsl_Location.get_gsl_library_dirs()
        if libraries is None:
            libraries = []
        # libraries.append('pygsl_lite')
        libraries.extend(gsl_Location.get_gsl_lib_list())

        # test if Numeric module is available
        if define_macros is None:
            define_macros = []
        define_macros = define_macros + [
            ("NUMERIC", 0),
        ]
        if undef_macros == None:
            undef_macros = []
        if "NDEBUG" not in undef_macros:
            undef_macros.append("NDEBUG")
        tmp = map(lambda x: x[0], define_macros)

        # Now config will test of GSL_MAJOR_VERSION and GSL_MINOR_VERSION is defined
        # if "PYGSL_GSL_MAJOR_VERSION" not in tmp:
        #        define_macros = define_macros + [("PYGSL_GSL_MAJOR_VERSION", gsl_major_version),]

        # if "PYGSL_GSL_MINOR_VERSION" not in tmp:
        #        #define_macros.append(("PYGSL_GSL_MINOR_VERSION", gsl_minor_version))
        #        define_macros = define_macros + [("PYGSL_GSL_MINOR_VERSION", gsl_minor_version),]

        # dependes triggers always a recompile ...
        # try to fix it
        # if depends is not None:
        # 	    depends = check_dependencies(sources, depends)

        Extension.__init__(
            self,
            name,
            sources,
            include_dirs,
            define_macros,
            undef_macros,
            library_dirs,
            libraries,
            runtime_library_dirs,
            extra_objects,
            extra_compile_args,
            extra_link_args,
            export_symbols,
            depends=depends,
            **kws,
        )

    def check_version(self, required_version, this_version):
        this_version = tuple(this_version)
        # print("req '%s' this '%s'" %(required_version, this_version))
        min_length = min(len(required_version), len(this_version))
        for pos in range(min_length):
            t_val = this_version[pos]
            test_val = required_version[pos]
            # print("\t %d: req '%s' this '%s'" %( pos, test_val, t_val))

            this_type = type(t_val)
            if this_type == type(" "):
                t_val = int(t_val)

            if type(test_val) == type(" "):
                test_val = int(test_val)

            if t_val > test_val:
                # already larger
                return 1
            elif t_val == test_val:
                continue
            elif t_val < test_val:
                return 0
            else:
                raise DistutilsExecError("incorrect version specification")
        # problematic: 0.9 < 0.9.0, but assures that 0.9.1 > 0.9
        if len(required_version) > len(this_version):
            return 0
        return 1

    def check_gsl_version(self, version_array):
        return self.check_version(version_array, self.get_gsl_version())

    def check_python_version(self, version_array):
        return self.check_version(version_array, version_info)

    # get gsl-prefix option
    def get_gsl_info(self, arguments):
        """
        executes gsl-config with given arguments
        """
        gsl_command = os.popen(self.gsl_config_tool + " " + arguments)
        gsl_output = gsl_command.readline()
        gsl_command.close()
        if not gsl_output:
            raise DistutilsExecError("could not start %s" % self.gsl_config_tool)
        return gsl_output

    def get_gsl_prefix(
        self,
    ):
        return gsl_Location.get_gsl_prefix()

    def get_gsl_cflags(self):
        return gsl_Location.get_gsl_cflags()

    def get_gsl_libs(self):
        return gsl_Location.get_gsl_libs()

    def get_gsl_version(self):
        return gsl_Location.get_gsl_version()
