import os
import platform
import site

from setuptools import setup, find_packages, Extension

SYS_PLATFORM = platform.system().lower()
IS_LINUX = 'linux' in SYS_PLATFORM
IS_OSX = 'darwin' == SYS_PLATFORM
IS_WIN = 'windows' == SYS_PLATFORM

# Get Numpy include path without importing it
NUMPY_INC_PATHS = [os.path.join(r, 'numpy', 'core', 'include')
                   for r in site.getsitepackages() if
                   os.path.isdir(os.path.join(r, 'numpy', 'core', 'include'))]
if len(NUMPY_INC_PATHS) == 0:
    try:
        import numpy as np
    except ImportError:
        raise ValueError("Could not find numpy include dir and numpy not installed before build - "
                         "cannot proceed with compilation of cython modules.")
    else:
        # just ask numpy for it's include dir
        NUMPY_INC_PATHS = [np.get_include()]

elif len(NUMPY_INC_PATHS) > 1:
    print("Found {} numpy include dirs: "
          "{}".format(len(NUMPY_INC_PATHS), ', '.join(NUMPY_INC_PATHS)))
    print("Taking first (highest precedence on path): {}".format(
        NUMPY_INC_PATHS[0]))
NUMPY_INC_PATH = NUMPY_INC_PATHS[0]


# ---- C/C++ EXTENSIONS ---- #
# Stolen (and modified) from the Cython documentation:
#     http://cython.readthedocs.io/en/latest/src/reference/compilation.html
def no_cythonize(extensions, **_ignore):
    import os.path as op
    for extension in extensions:
        sources = []
        for sfile in extension.sources:
            path, ext = os.path.splitext(sfile)
            if ext in ('.pyx', '.py'):
                if extension.language == 'c++':
                    ext = '.cpp'
                else:
                    ext = '.c'
                sfile = path + ext
                if not op.exists(sfile):
                    raise ValueError('Cannot find pre-compiled source file '
                                     '({}) - please install Cython'.format(sfile))
            sources.append(sfile)
        extension.sources[:] = sources
    return extensions


def build_extension_from_pyx(pyx_path, extra_sources_paths=None):
    # If we are building from the conda folder,
    # then we know we can manually copy some files around
    # because we have control of the setup. If you are
    # building this manually or pip installing, you must satisfy
    # that the vlfeat vl folder is on the PATH (for the headers)
    # and that the vl.dll file is visible to the build system
    # as well.
    include_dirs = [NUMPY_INC_PATH]
    library_dirs = []
    if IS_WIN:
        include_dirs.append(os.environ['LIBRARY_INC'])
        library_dirs.append(os.environ['LIBRARY_BIN'])

    if extra_sources_paths is None:
        extra_sources_paths = []
    extra_sources_paths.insert(0, pyx_path)
    ext = Extension(name=pyx_path[:-4].replace('/', '.'),
                    sources=extra_sources_paths,
                    include_dirs=include_dirs,
                    library_dirs=library_dirs,
                    libraries=['vl'],
                    language='c')
    if IS_LINUX or IS_OSX:
        ext.extra_compile_args.extend([
            '-Wno-unused-function',
            '-Wno-implicit-function-declaration'
    ])
    if IS_OSX:
        ext.extra_link_args.append('-headerpad_max_install_names')
    return ext


try:
    from Cython.Build import cythonize
except ImportError:
    import warnings

    cythonize = no_cythonize
    warnings.warn('Unable to import Cython - attempting to build using the '
                  'pre-compiled C++ files.')

cython_modules = [
    build_extension_from_pyx('cyvlfeat/fisher/cyfisher.pyx'),
    build_extension_from_pyx('cyvlfeat/generic/generic.pyx'),
    build_extension_from_pyx('cyvlfeat/gmm/cygmm.pyx'),
    build_extension_from_pyx('cyvlfeat/hog/cyhog.pyx'),
    build_extension_from_pyx('cyvlfeat/kmeans/cykmeans.pyx'),
    build_extension_from_pyx('cyvlfeat/quickshift/cyquickshift.pyx'),
    build_extension_from_pyx('cyvlfeat/sift/cysift.pyx'),
    build_extension_from_pyx('cyvlfeat/vlad/cyvlad.pyx'),
]
cython_exts = cythonize(cython_modules, quiet=True, language_level="3")


def get_version_and_cmdclass(package_name):
    import os
    from importlib.util import module_from_spec, spec_from_file_location
    spec = spec_from_file_location('version',
                                   os.path.join(package_name, '_version.py'))
    module = module_from_spec(spec)
    spec.loader.exec_module(module)
    return module.__version__, module.cmdclass


version, cmdclass = get_version_and_cmdclass('cyvlfeat')
setup(
    name='cyvlfeat',
    version=version,
    cmdclass=cmdclass,
    description='Cython wrapper of the VLFeat toolkit',
    url='https://github.com/menpo/cyvlfeat',
    author='Patrick Snape',
    author_email='patricksnape@gmail.com',
    ext_modules=cython_exts,
    package_data={'cyvlfeat': ['data/*.mat', 'data/ascent.descr', 'data/ascent.frame']},
    packages=find_packages()
)
