#!/usr/bin/env python

import glob
import os
import shutil
import sys
import platform

from distutils import log
from setuptools import setup
from distutils.util import get_platform
from distutils.command.build import build
from distutils.command.sdist import sdist
from setuptools.command.bdist_egg import bdist_egg

SYSTEM = sys.platform
VERSION = '4.0.0'

# adapted from commit e504b81 of Nguyen Tan Cong
# Reference: https://docs.python.org/2/library/platform.html#cross-platform
IS_64BITS = sys.maxsize > 2**32

# are we building from the repository or from a source distribution?
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
LIBS_DIR = os.path.join(ROOT_DIR, 'capstone', 'lib')
HEADERS_DIR = os.path.join(ROOT_DIR, 'capstone', 'include')
SRC_DIR = os.path.join(ROOT_DIR, 'src')
BUILD_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')

if SYSTEM == 'darwin':
    VERSIONED_LIBRARY_FILE = "libcapstone.4.dylib"
    LIBRARY_FILE = "libcapstone.dylib"
    STATIC_LIBRARY_FILE = 'libcapstone.a'
elif SYSTEM in ('win32', 'cygwin'):
    VERSIONED_LIBRARY_FILE = "capstone.dll"
    LIBRARY_FILE = "capstone.dll"
    STATIC_LIBRARY_FILE = None
else:
    VERSIONED_LIBRARY_FILE = "libcapstone.so.4"
    LIBRARY_FILE = "libcapstone.so"
    STATIC_LIBRARY_FILE = 'libcapstone.a'

def clean_bins():
    shutil.rmtree(LIBS_DIR, ignore_errors=True)
    shutil.rmtree(HEADERS_DIR, ignore_errors=True)

def copy_sources():
    """Copy the C sources into the source directory.
    This rearranges the source files under the python distribution
    directory.
    """
    src = []

    try:
        shutil.rmtree("src/")
    except (IOError, OSError):
        pass

    shutil.copytree(os.path.join(BUILD_DIR, "arch"), os.path.join(SRC_DIR, "arch"))
    shutil.copytree(os.path.join(BUILD_DIR, "include"), os.path.join(SRC_DIR, "include"))

    src.extend(glob.glob(os.path.join(BUILD_DIR, "*.[ch]")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "*.mk")))

    src.extend(glob.glob(os.path.join(BUILD_DIR, "Makefile")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "LICENSE*")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "README")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "*.TXT")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "RELEASE_NOTES")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "make.sh")))
    src.extend(glob.glob(os.path.join(BUILD_DIR, "CMakeLists.txt")))

    for filename in src:
        outpath = os.path.join(SRC_DIR, os.path.basename(filename))
        log.info("%s -> %s" % (filename, outpath))
        shutil.copy(filename, outpath)

def build_libraries():
    """
    Prepare the capstone directory for a binary distribution or installation.
    Builds shared libraries and copies header files.

    Will use a src/ dir if one exists in the current directory, otherwise assumes it's in the repo
    """
    cwd = os.getcwd()
    clean_bins()
    os.mkdir(HEADERS_DIR)
    os.mkdir(LIBS_DIR)

    # copy public headers
    shutil.copytree(os.path.join(BUILD_DIR, 'include', 'capstone'), os.path.join(HEADERS_DIR, 'capstone'))

    os.chdir(BUILD_DIR)

    # platform description refers at https://docs.python.org/2/library/sys.html#sys.platform
    if SYSTEM == "win32":
        # Windows build: this process requires few things:
        #    - CMake + MSVC installed
        #    - Run this command in an environment setup for MSVC
        if not os.path.exists("build"): os.mkdir("build")
        os.chdir("build")
        # Do not build tests & static library
        os.system('cmake -DCMAKE_BUILD_TYPE=RELEASE -DCAPSTONE_BUILD_TESTS=0 -DCAPSTONE_BUILD_STATIC=0 -G "NMake Makefiles" ..')
        os.system("nmake")
    else:   # Unix incl. cygwin
        os.system("CAPSTONE_BUILD_CORE_ONLY=yes bash ./make.sh")

    shutil.copy(VERSIONED_LIBRARY_FILE, os.path.join(LIBS_DIR, LIBRARY_FILE))
    if STATIC_LIBRARY_FILE: shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
    os.chdir(cwd)


class custom_sdist(sdist):
    def run(self):
        clean_bins()
        copy_sources()
        return sdist.run(self)


class custom_build(build):
    def run(self):
        log.info('Building C extensions')
        build_libraries()
        return build.run(self)


class custom_bdist_egg(bdist_egg):
    def run(self):
        self.run_command('build')
        return bdist_egg.run(self)

def dummy_src():
    return []

cmdclass = {}
cmdclass['build'] = custom_build
cmdclass['sdist'] = custom_sdist
cmdclass['bdist_egg'] = custom_bdist_egg

try:
    from setuptools.command.develop import develop
    class custom_develop(develop):
        def run(self):
            log.info("Building C extensions")
            build_libraries()
            return develop.run(self)

    cmdclass['develop'] = custom_develop
except ImportError:
    print("Proper 'develop' support unavailable.")

if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
    idx = sys.argv.index('bdist_wheel') + 1
    sys.argv.insert(idx, '--plat-name')
    name = get_platform()
    if 'linux' in name:
        # linux_* platform tags are disallowed because the python ecosystem is fubar
        # linux builds should be built in the centos 5 vm for maximum compatibility
        # see https://github.com/pypa/manylinux
        # see also https://github.com/angr/angr-dev/blob/master/bdist.sh
        sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine())
    else:
        # https://www.python.org/dev/peps/pep-0425/
        sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_'))

setup(
    provides=['capstone'],
    packages=['capstone'],
    name='capstone',
    version=VERSION,
    author='Nguyen Anh Quynh',
    author_email='aquynh@gmail.com',
    description='Capstone disassembly engine',
    url='http://www.capstone-engine.org',
    classifiers=[
        'License :: OSI Approved :: BSD License',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 3',
    ],
    requires=['ctypes'],
    cmdclass=cmdclass,
    zip_safe=True,
    include_package_data=True,
    package_data={
        "capstone": ["lib/*", "include/capstone/*"],
    }
)
