#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
setup.py file for @SICONOS_PYTHON_PACKAGE@ python package

This uses Distutils (http://python.org/sigs/distutils-sig/) the standard
python mechanism for installing packages. For the easiest installation
just type the command (you'll probably need root privileges for that):

    python setup.py install

This will install the library in the default location. For instructions on
how to customize the install procedure read the output of:

    python setup.py --help install

In addition, there are some other commands:

    python setup.py clean -> will clean all trash (*.pyc and stuff)
    python setup.py test  -> will run the complete test suite
    python setup.py bench -> will run the complete benchmark suite

To get a full list of avaiable commands, read the output of:

    python setup.py --help-commands

"""
from numpy.distutils.core import setup, Extension
from numpy.distutils.command.build_py import build_py
from distutils.core import Command
from distutils.command.install_lib import install_lib
from distutils import dir_util
from distutils.core import Command
from distutils.file_util import copy_file
from numpy.distutils.misc_util import Configuration
import numpy as np
import glob
import os
import sys

# Modified from distutils.dir_util to not attempt to overwrite
# symlinks if already present.
def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
              preserve_symlinks=0, update=0, verbose=1, dry_run=0):
    if not dry_run and not os.path.isdir(src):
        raise DistutilsFileError("cannot copy tree '%s': not a directory" % src)
    try:
        names = os.listdir(src)
    except os.error as er:
        (errno, errstr) = er
        if dry_run:
            names = []
        else:
            raise DistutilsFileError("error listing files in '%s': %s" % (src, errstr))

    if not dry_run:
        dir_util.mkpath(dst, verbose=verbose)

    outputs = []

    for n in names:
        src_name = os.path.join(src, n)
        dst_name = os.path.join(dst, n)

        if n.startswith('.nfs'):
            # skip NFS rename files
            continue

        if preserve_symlinks and os.path.islink(src_name):
            link_dest = os.readlink(src_name)
            if not dry_run:
                if os.path.exists(dst_name):
                    if os.readlink(dst_name) != link_dest:
                        os.remove(dst_name)
                        if verbose >= 1:
                            dir_util.log.info("linking %s -> %s", dst_name, link_dest)
                        os.symlink(link_dest, dst_name)
                    elif verbose >= 1:
                        dir_util.log.info("leaving %s -> %s", dst_name, link_dest)
                else:
                    if verbose >= 1:
                        dir_util.log.info("linking %s -> %s", dst_name, link_dest)
                    os.symlink(link_dest, dst_name)
            outputs.append(dst_name)

        elif os.path.isdir(src_name):
            outputs.extend(
                copy_tree(src_name, dst_name, preserve_mode,
                          preserve_times, preserve_symlinks, update,
                          verbose=verbose, dry_run=dry_run))
        else:
            copy_file(src_name, dst_name, preserve_mode,
                      preserve_times, update, verbose=verbose,
                      dry_run=dry_run)
            outputs.append(dst_name)

    return outputs

# Make sure I have the right Python version.
if sys.version_info[:2] < (2,6):
    print("Siconos requires Python 2.6 or newer. Python %d.%d detected".format(
        sys.version_info[0], sys.version_info[1]))
    sys.exit(-1)


class PyTest(Command):
    """To run tests using 'python setup.py test'
    """
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        import subprocess
        import sys
        errno = subprocess.call([sys.executable, 'runtests.py', 'build', '-s'])
        raise SystemExit(errno)

class clean(Command):
    """Cleans *.pyc and debian trashs, so you should get the same copy as
    is in the VCS.
    """

    description = "remove build files"
    user_options = [("all","a","the same")]

    def initialize_options(self):
        self.all = None

    def finalize_options(self):
        pass

    def run(self):
        import os
        os.system("py.cleanup")
        os.system("rm -f python-build-stamp-2.4")
        os.system("rm -f MANIFEST")
        os.system("rm -rf build")
        os.system("rm -rf dist")
        os.system("rm -rf doc/_build")

class build_py_symlink(build_py):
    def build_module(self, module, module_file, package):
        if isinstance(package, str):
            package = package.split('.')
        elif not isinstance(package, (list, tuple)):
            raise TypeError(
                "'package' must be a string (dot-separated), list, or tuple")

        # Now put the module source file into the "build" area -- this is
        # easy, we just copy it somewhere under self.build_lib (the build
        # directory for Python source).
        outfile = self.get_module_outfile(self.build_lib, package, module)
        dir = os.path.dirname(outfile)
        self.mkpath(dir)
        if os.path.exists(outfile) and os.path.realpath(outfile) != module_file:
            os.remove(outfile)
        return copy_file(module_file, outfile, preserve_mode=0,
                         link='sym', update=True, verbose=1)

class install_lib_symlink(install_lib):
    def install(self):
        if os.path.isdir(self.build_dir):
            outfiles = copy_tree(self.build_dir, self.install_dir,
                                 preserve_symlinks=True, update=True, verbose=1)
        else:
            self.warn("'%s' does not exist -- no Python modules to install" %
                      self.build_dir)
            return
        return outfiles

class TestSiconos(Command):
    """Runs all tests under the tests/ folder
    """

    description = "Run all tests and doctests; also see bin/test and bin/doctest"
    user_options = []  # distutils complains if this is not here.

    def __init__(self, *args):
        self.args = args[0] # so we can pass it to other classes
        Command.__init__(self, *args)

    def initialize_options(self):  # distutils wants this
        pass

    def finalize_options(self):    # this too
        pass

    def run(self):
        from subprocess import call
        # hu?
        call("py.test" + " siconos/tests", shell=True, env={"PYTHONPATH": "${CMAKE_BINARY_DIR}/wrap/"})


def get_cmake_option(option):
    opt = option.upper()
    return opt == "ON" or opt == "1" or opt == "TRUE"

# Full package name
name = '@SICONOS_PYTHON_PACKAGE@'
# List of python modules (directories) to be included
packages = ['siconos',
            ]

with_component = {}
components_list = "@SICONOS_PYTHON_MODULES@"

# kernel, numerics and io are just 'so' in siconos.
# This will probably change if we split each python interface for those packages.
#with_component['numerics'] = True
#with_component['kernel'] = "@HAVE_SICONOS_KERNEL@" is "TRUE"
with_component['control'] = get_cmake_option("@HAVE_SICONOS_CONTROL@")
with_component['mechanics'] = get_cmake_option("@HAVE_SICONOS_MECHANICS@")
with_component['io'] = get_cmake_option("@HAVE_SICONOS_IO@")
with_component['mechanisms'] = get_cmake_option("@HAVE_SICONOS_MECHANISMS@")
with_bullet = get_cmake_option("@WITH_BULLET@")
with_oce = get_cmake_option("@WITH_OCE@")
packages_for_tests = []
with_testing = get_cmake_option("@WITH_TESTING@")
if with_testing:
    packages_for_tests.append('siconos.tests')

for comp in list(with_component.keys()):
    if with_component[comp]:
        packages.append('siconos.' + comp)

if with_component['mechanics']:
    packages.append('siconos.mechanics.collision')


packages += packages_for_tests

# Enable this to get debug info
DISTUTILS_DEBUG = 1

# C files and swig interface
# swig =''
# for mod in packages_src_dirs:
#     swig_dir = os.path.join(os.path.join('@CMAKE_SOURCE_DIR@', mod), 'swig')

#extra_link_args = ['-lopenblas', '-lgomp']
#swig_opts = ['-modern', '-I./']


#swig_ext = Extension('_numerics', swig, language='c++',
#                     swig_opts=swig_opts,
#                     extra_link_args=extra_link_args,
#                     extra_compile_args=[''])

ext_modules = []
include_dirs = [np.get_include()]
descr = 'Python bindings for the @PROJECT_NAME@ software.'
authors = 'Siconos team.'
cmdclass={'test': PyTest,
          'clean': clean}
try:
    install_symlinks = ("@INSTALL_PYTHON_SYMLINKS@".lower()=='on'
                        or "@INSTALL_PYTHON_SYMLINKS@".lower()=='true'
                        or int("@INSTALL_PYTHON_SYMLINKS@")!=0)
except ValueError:
    install_symlinks = False
if install_symlinks:
    cmdclass['build_py'] = build_py_symlink
    cmdclass['install_lib'] = install_lib_symlink
config = Configuration(
    name=name,
    version='@SICONOS_VERSION@',
    description=descr,
    author=authors,
    author_email='siconos-team@lists.gforge.fr',
    url='http://siconos.gforge.inria.fr',
    package_dir={'': '@CMAKE_CURRENT_BINARY_DIR@'},
    ext_modules=ext_modules,
    packages=packages,
    py_modules=[],
    include_dirs=include_dirs,
    cmdclass=cmdclass,
    classifiers=['License :: OSI Approved :: Apache Software License',
                 'Operating System :: MacOS',
                 'Operating System :: Microsoft :: Windows',
                 'Operating System :: POSIX :: Linux',
                 'Topic :: Scientific/Engineering :: Mathematics',
                 'Topic :: Scientific/Engineering :: Physics']
)

setup(**config.todict())
