from __future__ import print_function

import ast
import atexit
import distutils.cmd
import distutils.log
import distutils.sysconfig
import os.path
import platform
import shutil
import subprocess
import sys
import tempfile

from setuptools import Extension, setup

MACOS_FLAG = ['-mmacosx-version-min=10.7']
FLAGS_POSIX = [
    '-fPIC', '-std=gnu++0x', '-Wall', '-Wno-parentheses', '-Werror=switch',
]
FLAGS_CLANG = ['-c', '-O3'] + FLAGS_POSIX + ['-stdlib=libc++']
LFLAGS_POSIX = ['-fPIC',  '-lstdc++']
LFLAGS_CLANG = ['-fPIC', '-stdlib=libc++']

sources = ['_sass.c']
headers = []

if sys.platform == 'win32':
    extra_compile_args = ['/Od', '/EHsc', '/MT']
    extra_link_args = []
elif platform.system() == 'Darwin':
    extra_compile_args = FLAGS_CLANG + MACOS_FLAG
    extra_link_args = LFLAGS_CLANG + MACOS_FLAG
elif platform.system() == 'FreeBSD':
    extra_compile_args = FLAGS_CLANG
    extra_link_args = LFLAGS_CLANG
else:
    extra_compile_args = FLAGS_POSIX
    extra_link_args = LFLAGS_POSIX

if platform.system() in {'Darwin', 'FreeBSD'}:
    os.environ.setdefault('CC', 'clang')
    os.environ.setdefault('CXX', 'clang++')
    orig_customize_compiler = distutils.sysconfig.customize_compiler

    def customize_compiler(compiler):
        orig_customize_compiler(compiler)
        compiler.compiler[0] = os.environ['CC']
        compiler.compiler_so[0] = os.environ['CXX']
        compiler.compiler_cxx[0] = os.environ['CXX']
        compiler.linker_so[0] = os.environ['CXX']
        return compiler
    distutils.sysconfig.customize_compiler = customize_compiler

if os.environ.get('SYSTEM_SASS', False):
    libraries = ['sass']
    include_dirs = []
else:
    LIBSASS_SOURCE_DIR = os.path.join('libsass', 'src')

    if (
            not os.path.isfile(os.path.join('libsass', 'Makefile')) and
            os.path.isdir('.git')
    ):
        print(file=sys.stderr)
        print('Missing the libsass sumbodule.  Try:', file=sys.stderr)
        print('  git submodule update --init', file=sys.stderr)
        print(file=sys.stderr)
        exit(1)

    # Determine the libsass version from the git checkout
    if os.path.exists(os.path.join('libsass', '.git')):
        out = subprocess.check_output((
            'git', '-C', 'libsass', 'describe',
            '--abbrev=4', '--dirty', '--always', '--tags',
        ))
        with open('.libsass-upstream-version', 'wb') as libsass_version_file:
            libsass_version_file.write(out)

    # The version file should always exist at this point
    with open('.libsass-upstream-version', 'rb') as libsass_version_file:
        libsass_version = libsass_version_file.read().decode('UTF-8').strip()
        if sys.platform == 'win32':
            # This looks wrong, but is required for some reason :(
            define = r'/DLIBSASS_VERSION="\"{}\""'.format(libsass_version)
        else:
            define = '-DLIBSASS_VERSION="{}"'.format(libsass_version)

    for directory in (
            os.path.join('libsass', 'src'),
            os.path.join('libsass', 'include'),
    ):
        for pth, _, filenames in os.walk(directory):
            for filename in filenames:
                filename = os.path.join(pth, filename)
                if filename.endswith(('.c', '.cpp')):
                    sources.append(filename)
                elif filename.endswith('.h'):
                    headers.append(filename)

    if sys.platform == 'win32':
        from distutils.msvc9compiler import get_build_version
        vscomntools_env = 'VS{}{}COMNTOOLS'.format(
            int(get_build_version()),
            int(get_build_version() * 10) % 10,
        )
        try:
            os.environ[vscomntools_env] = os.environ['VS140COMNTOOLS']
        except KeyError:
            distutils.log.warn(
                'You probably need Visual Studio 2015 (14.0) '
                'or higher',
            )
        from distutils import msvccompiler, msvc9compiler
        if msvccompiler.get_build_version() < 14.0:
            msvccompiler.get_build_version = lambda: 14.0
        if get_build_version() < 14.0:
            msvc9compiler.get_build_version = lambda: 14.0
            msvc9compiler.VERSION = 14.0
    elif platform.system() in ('Darwin', 'FreeBSD'):
        # Dirty workaround to avoid link error...
        # Python distutils doesn't provide any way
        # to configure different flags for each cc and c++.
        cencode_path = os.path.join(LIBSASS_SOURCE_DIR, 'cencode.c')
        cencode_body = ''
        with open(cencode_path) as f:
            cencode_body = f.read()
        with open(cencode_path, 'w') as f:
            f.write(
                '#ifdef __cplusplus\n'
                'extern "C" {\n'
                '#endif\n',
            )
            f.write(cencode_body)
            f.write(
                '#ifdef __cplusplus\n'
                '}\n'
                '#endif\n',
            )

        @atexit.register
        def restore_cencode():
            if os.path.isfile(cencode_path):
                with open(cencode_path, 'w') as f:
                    f.write(cencode_body)

    libraries = []
    include_dirs = [os.path.join('.', 'libsass', 'include')]
    extra_compile_args.append(define)

# Py_LIMITED_API does not work for pypy
# https://foss.heptapod.net/pypy/pypy/issues/3173
if not hasattr(sys, 'pypy_version_info'):
    py_limited_api = True
    define_macros = [('Py_LIMITED_API', None)]
else:
    py_limited_api = False
    define_macros = []

sass_extension = Extension(
    '_sass',
    sorted(sources),
    include_dirs=include_dirs,
    depends=headers,
    extra_compile_args=extra_compile_args,
    extra_link_args=extra_link_args,
    libraries=libraries,
    py_limited_api=py_limited_api,
    define_macros=define_macros,
)


def version(sass_filename='sass.py'):
    with open(sass_filename) as f:
        tree = ast.parse(f.read(), sass_filename)
    for node in tree.body:
        if isinstance(node, ast.Assign) and len(node.targets) == 1:
            target, = node.targets
            if isinstance(target, ast.Name) and target.id == '__version__':
                return node.value.s


def readme():
    try:
        with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as f:
            return f.read()
    except IOError:
        pass


class upload_doc(distutils.cmd.Command):
    """Uploads the documentation to GitHub pages."""

    description = __doc__
    user_options = []

    def initialize_options(self):
        if sys.version_info < (3,):
            raise SystemExit('upload_doc must be run with python 3')

    def finalize_options(self):
        pass

    def run(self):
        path = tempfile.mkdtemp()
        build = os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            'build', 'sphinx', 'html',
        )
        os.chdir(path)
        os.system(
            'git clone -b gh-pages --depth 5 '
            'git@github.com:sass/libsass-python.git .',
        )
        os.system('git rm -r .')
        os.system('touch .nojekyll')
        os.system('cp -r ' + build + '/* .')
        os.system('git stage .')
        os.system('git commit -a -m "Documentation updated."')
        os.system('git push origin gh-pages')
        shutil.rmtree(path)


cmdclass = {'upload_doc': upload_doc}

if (
        sys.platform != 'win32' and
        sys.version_info >= (3,) and
        platform.python_implementation() == 'CPython'
):
    try:
        import wheel.bdist_wheel
    except ImportError:
        pass
    else:
        class bdist_wheel(wheel.bdist_wheel.bdist_wheel):
            def finalize_options(self):
                self.py_limited_api = 'cp3{}'.format(sys.version_info[1])
                super().finalize_options()

        cmdclass['bdist_wheel'] = bdist_wheel


setup(
    name='libsass',
    description='Sass for Python: '
                'A straightforward binding of libsass for Python.',
    long_description=readme(),
    version=version(),
    ext_modules=[sass_extension],
    packages=['sassutils'],
    py_modules=['pysassc', 'sass', 'sassc', 'sasstests'],
    package_data={
        '': [
            'README.rst',
            'test/*.sass',
        ],
    },
    license='MIT License',
    author='Hong Minhee',
    author_email='minhee' '@' 'dahlia.kr',
    url='https://sass.github.io/libsass-python/',
    download_url='https://github.com/sass/libsass-python/releases',
    entry_points={
        'distutils.commands': [
            'build_sass = sassutils.distutils:build_sass',
        ],
        'distutils.setup_keywords': [
            'sass_manifests = sassutils.distutils:validate_manifests',
        ],
        'console_scripts': [
            ['pysassc = pysassc:main'],
            # TODO: remove `sassc` entry (#134)
            ['sassc = sassc:main'],
        ],
    },
    install_requires=['six'],
    classifiers=[
        'Development Status :: 5 - Production/Stable',
        'Environment :: Web Environment',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
        'Programming Language :: C',
        'Programming Language :: C++',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
        'Programming Language :: Python :: Implementation :: CPython',
        'Programming Language :: Python :: Implementation :: PyPy',
        'Programming Language :: Python :: Implementation :: Stackless',
        'Topic :: Internet :: WWW/HTTP',
        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
        'Topic :: Software Development :: Code Generators',
        'Topic :: Software Development :: Compilers',
    ],
    cmdclass=cmdclass,
)
