import distutils
from distutils.core import setup, Extension
from distutils.command.build_ext import build_ext
from distutils.cmd import Command
import platform
import os
import re


CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))

# when compiling for Windows Python 2.7, force distutils to use Visual Studio
# 2010 instead of 2008, as the latter doesn't support c++0x
if platform.system() == 'Windows':
    try:
        import distutils.msvc9compiler
    except distutils.errors.DistutilsPlatformError:
        pass  # importing msvc9compiler raises when running under MinGW
    else:
        orig_find_vcvarsall = distutils.msvc9compiler.find_vcvarsall
        def patched_find_vcvarsall(version):
            return orig_find_vcvarsall(version if version != 9.0 else 10.0)
        distutils.msvc9compiler.find_vcvarsall = patched_find_vcvarsall


def get_version():
    """ Return BROTLI_VERSION string as defined in 'brotlimodule.cc' file. """
    brotlimodule = os.path.join(CURR_DIR, 'python', 'brotlimodule.cc')
    with open(brotlimodule, 'r') as f:
        for line in f:
            m = re.match(r'#define\sBROTLI_VERSION\s"(.*)"', line)
            if m:
                return m.group(1)
    return ""


class TestCommand(Command):
    """ Run all *_test.py scripts in 'tests' folder with the same Python
    interpreter used to run setup.py.
    """

    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        import sys, subprocess, glob

        test_dir = os.path.join(CURR_DIR, 'python', 'tests')
        os.chdir(test_dir)

        for test in glob.glob("*_test.py"):
            try:
                subprocess.check_call([sys.executable, test])
            except subprocess.CalledProcessError:
                raise SystemExit(1)


class BuildExt(build_ext):
    def get_source_files(self):
        filenames = build_ext.get_source_files(self)
        for ext in self.extensions:
            filenames.extend(ext.depends)
        return filenames

    def build_extension(self, ext):
        c_sources = []
        cxx_sources = []
        for source in ext.sources:
            if source.endswith(".c"):
                c_sources.append(source)
            else:
                cxx_sources.append(source)
        extra_args = ext.extra_compile_args or []

        objects = []
        for lang, sources in (("c", c_sources), ("c++", cxx_sources)):
            if lang == "c++": 
                if platform.system() == "Darwin":
                    extra_args.extend(["-stdlib=libc++", "-mmacosx-version-min=10.7"])
                if self.compiler.compiler_type in ["unix", "cygwin", "mingw32"]:
                    extra_args.append("-std=c++0x")
                elif self.compiler.compiler_type == "msvc":
                    extra_args.append("/EHsc")

            macros = ext.define_macros[:]
            if platform.system() == "Darwin":
                macros.append(("OS_MACOSX", "1"))
            elif self.compiler.compiler_type == "mingw32":
                # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot",
                # This clashes with GCC's cmath, and causes compilation errors when
                # building under MinGW: http://bugs.python.org/issue11566
                macros.append(("_hypot", "hypot"))
            for undef in ext.undef_macros:
                macros.append((undef,))

            objs = self.compiler.compile(sources,
                                         output_dir=self.build_temp,
                                         macros=macros,
                                         include_dirs=ext.include_dirs,
                                         debug=self.debug,
                                         extra_postargs=extra_args,
                                         depends=ext.depends)
            objects.extend(objs)

        self._built_objects = objects[:]
        if ext.extra_objects:
            objects.extend(ext.extra_objects)
        extra_args = ext.extra_link_args or []
        # when using GCC on Windows, we statically link libgcc and libstdc++,
        # so that we don't need to package extra DLLs
        if self.compiler.compiler_type == "mingw32":
            extra_args.extend(['-static-libgcc', '-static-libstdc++'])

        ext_path = self.get_ext_fullpath(ext.name)
        # Detect target language, if not provided
        language = ext.language or self.compiler.detect_language(sources)

        self.compiler.link_shared_object(
            objects, ext_path,
            libraries=self.get_libraries(ext),
            library_dirs=ext.library_dirs,
            runtime_library_dirs=ext.runtime_library_dirs,
            extra_postargs=extra_args,
            export_symbols=self.get_export_symbols(ext),
            debug=self.debug,
            build_temp=self.build_temp,
            target_lang=language)

brotli = Extension("brotli",
                    sources=[
                        "python/brotlimodule.cc",
                        "enc/backward_references.cc",
                        "enc/block_splitter.cc",
                        "enc/brotli_bit_stream.cc",
                        "enc/encode.cc",
                        "enc/entropy_encode.cc",
                        "enc/histogram.cc",
                        "enc/literal_cost.cc",
                        "enc/metablock.cc",
                        "enc/static_dict.cc",
                        "enc/streams.cc",
                        "dec/bit_reader.c",
                        "dec/decode.c",
                        "dec/huffman.c",
                        "dec/streams.c",
                        "dec/state.c",
                    ],
                    depends=[
                        "enc/backward_references.h",
                        "enc/bit_cost.h",
                        "enc/block_splitter.h",
                        "enc/brotli_bit_stream.h",
                        "enc/cluster.h",
                        "enc/command.h",
                        "enc/context.h",
                        "enc/dictionary.h",
                        "enc/dictionary_hash.h",
                        "enc/encode.h",
                        "enc/entropy_encode.h",
                        "enc/fast_log.h",
                        "enc/find_match_length.h",
                        "enc/hash.h",
                        "enc/histogram.h",
                        "enc/literal_cost.h",
                        "enc/metablock.h",
                        "enc/port.h",
                        "enc/prefix.h",
                        "enc/ringbuffer.h",
                        "enc/static_dict.h",
                        "enc/static_dict_lut.h",
                        "enc/streams.h",
                        "enc/transform.h",
                        "enc/write_bits.h",
                        "dec/bit_reader.h",
                        "dec/context.h",
                        "dec/decode.h",
                        "dec/dictionary.h",
                        "dec/huffman.h",
                        "dec/prefix.h",
                        "dec/port.h",
                        "dec/streams.h",
                        "dec/transform.h",
                        "dec/types.h",
                        "dec/state.h",
                    ],
                    language="c++",
                    )

setup(
    name="Brotli",
    version=get_version(),
    url="https://github.com/google/brotli",
    description="Python binding of the Brotli compression library",
    author="Khaled Hosny",
    author_email="khaledhosny@eglug.org",
    license="Apache 2.0",
    ext_modules=[brotli],
    cmdclass={
        'build_ext': BuildExt,
        'test': TestCommand
        },
)
