#!/usr/bin/env python
"""%prog [--target=STRING] [--prefix=PATH]"""

from optparse import OptionParser
import os
import sys


def sub(filename, variables):
    if not os.path.isfile(filename + '.in'):
        raise Exception("cannot find %s.in" % filename)
    with open(filename + '.in') as f_template:
        with open(filename, 'wb') as fd:
            print "Creating %s" % filename
            fd.write(f_template.read() % variables)


def version_greater_than(left, right):
    left = left.split('.')
    right = right.split('.')

    for index, _ in enumerate(left):
        if int(left[index]) > int(right[index]):
            return True
        elif int(left[index]) < int(right[index]):
            return False


def locate_exec(prog):

    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(prog)
    if fpath:
        # Full path given, check if executable
        if is_exe(prog):
            return prog
    else:
        # Check for all directories listed in $PATH
        for pathdir in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(pathdir, prog)
            if is_exe(exe_file):
                return exe_file
    return ""


class ConfigureVariables(object):
    def __init__(self):
        self.values = {}

    def add_value(self, key, value, comment):
        print "+ %s: %s" % (comment, value)
        self.values[key] = value


SUPPORTED_TARGETS = ('aarch64-elf', 'arm-elf', 'erc32-elf', 'leon-elf',
                     'leon3-elf', 'p55-elf', 'ppc-elf',
                     'e500v2-vx6', 'ppc-vx6',
                     'ppc-vx653',
                     'x86-linux',
                     'aarch64-vx7', 'ppc-vx7', 'ppc64-vx7', 'x86-vx7',
                     'x86_64-vx7')

if __name__ == "__main__":
    parser = OptionParser(usage=sys.modules['__main__'].__doc__)
    parser.add_option("--target",
                      dest="target",
                      metavar="STRING",
                      default="ppc-elf",
                      help="set the target platform (%s)" %
                           "|".join(SUPPORTED_TARGETS))
    parser.add_option("--prefix",
                      dest="prefix",
                      metavar="PATH",
                      default="./install",
                      help="installation directory")
    parser.add_option("--with-qemu",
                      dest="qemu_install_dir",
                      metavar="PATH",
                      default=None,
                      help="Qemu installation directory")

    (options, args) = parser.parse_args()

    # Check that no positional parameter has been passed
    if len(args) > 0:
        parser.error("parameters not allowed")

    conf = ConfigureVariables()

    # Set gnatemulator version
    with open('./VERSION') as f:
        version = f.read().strip()
    conf.add_value('gnatemulator_version',
                   version,
                   'GNATEmulator version')

    # Same thing with date
    with open('./VERSION_DATE') as f:
        version_date = f.read().strip()
    conf.add_value('gnatemulator_date',
                   version_date,
                   'GNATEmulator date')

    # Resolve prefix to an absolute path
    conf.add_value('prefix',
                   os.path.abspath(options.prefix).replace('\\', '/'),
                   'Installation path')

    # Check that the selected target is valid
    if options.target not in SUPPORTED_TARGETS:
        # Check if we need to strip host information
        if options.target.endswith('-linux') or \
                options.target.endswith('-windows'):
            options.target = options.target.replace('-linux', '')
            options.target = options.target.replace('-windows', '')
            if options.target not in SUPPORTED_TARGETS:
                parser.error("target %s is not supported" % options.target)
    conf.add_value('target',
                   options.target,
                   'Selected target')

    program_prefix = {'ppc-elf':    'powerpc-elf-',
                      'leon-elf':   'leon-elf-',
                      'leon3-elf':  'leon3-elf-',
                      'erc32-elf':  'erc32-elf-',
                      'ppc-vx653':  'powerpc-wrs-vxworksae-',
                      'p55-elf':    'powerpc-eabispe-',
                      'e500v2-vx6': 'e500v2-wrs-vxworks-',
                      'ppc-vx6':    'powerpc-wrs-vxworks-',
                      'ppc-vx7':    'powerpc-wrs-vxworks7-',
                      'ppc64-vx7':  'powerpc64-wrs-vxworks7-',
                      'x86-linux':  '',
                      'x86-vx7':    'x86-wrs-vxworks7-',
                      'arm-elf':    'arm-eabi-',
                      'aarch64-elf': 'aarch64-elf-',
                      'aarch64-vx7': 'aarch64-wrs-vxworks7-',
                      'x86_64-vx7':  'x86_64-wrs-vxworks7-'}

    conf.add_value('program_prefix',
                   program_prefix[options.target],
                   'Prefix used for program names')

    # Find the extension of the executable on the host
    exe_ext = ''
    if sys.platform.startswith('win'):
        exe_ext = '.exe'

    conf.add_value('exe_ext',
                   exe_ext,
                   'Executable extension on the host')

    # Find the relevant qemu
    qemu_bin = []
    if options.target.startswith('ppc64'):
        qemu_bin = ['qemu-system-ppc64' + exe_ext]
    elif options.target.startswith('ppc') or \
            options.target.startswith('e500v2') or \
            options.target.startswith('p55'):
        qemu_bin = ['qemu-system-ppc' + exe_ext]
    elif options.target.startswith('leon') or \
            options.target.startswith('erc32'):
        qemu_bin = ['qemu-system-sparc' + exe_ext]
    elif options.target.startswith('x86-'):
        qemu_bin = ['qemu-system-i386' + exe_ext]
    elif options.target.startswith('x86_64-'):
        qemu_bin = ['qemu-system-x86_64' + exe_ext]
    elif options.target.startswith('arm'):
        qemu_bin = ['qemu-system-arm' + exe_ext, 'qemu-system-armeb' + exe_ext]
    elif options.target.startswith('aarch64'):
        qemu_bin = ['qemu-system-aarch64' + exe_ext]

    if options.qemu_install_dir:
        if os.path.isdir(options.qemu_install_dir):
            # The path passed to with-qemu option is a directory. Assume
            # qemu is in bin subdirectory
            qemu_bin = os.path.join(options.qemu_install_dir, 'bin', qemu_bin)
        else:
            # User pass a path to the qemu executable to use
            qemu_bin = options.qemu_install_dir
            if not qemu_bin.endswith(exe_ext):
                qemu_bin += exe_ext

        qemu_bin = [qemu_bin]

    build_qemu = 'false'
    qemu_configure_flags = []

    if os.path.isdir(os.path.join('qemu')) and not options.qemu_install_dir:
        # We have a subdirectory called qemu. So we should build qemu from
        # source
        build_qemu = 'true'

        # Now guess the build parameters for QEMU
        if not os.path.isfile(os.path.join('qemu', 'VERSION')):
            parser.error('invalid qemu source dir (cannot find VERSION file)')

        with open(os.path.join("qemu", 'VERSION')) as f:
            qemu_version = f.read().strip()

        with open(os.path.join("qemu", 'VERSION_DATE')) as f:
            qemu_version_date = f.read().strip()

        if version_greater_than(qemu_version, '0.14.0'):
            qemu_configure_flags += ['--disable-werror', '--disable-vnc']
        else:
            qemu_configure_flags += ['--disable-vnc-tls',
                                     '--disable-vnc-jpeg',
                                     '--disable-vnc-png',
                                     '--disable-vnc-thread',
                                     '--disable-vnc-sasl']

        if version_greater_than(qemu_version, '1.0.0'):
            qemu_configure_flags += ['--disable-bridge-helper']

        if version_greater_than(qemu_version, '1.7.0'):
            qemu_configure_flags += ['--disable-gtk',
                                     '--disable-tools',
                                     '--disable-rdma',
                                     '--disable-guest-agent']

        if version_greater_than(qemu_version, '1.9.9'):
            qemu_configure_flags += ['--disable-stack-protector']
            if sys.platform.startswith('win'):
                # QEMU Change-Log 2.0
                # On Win32, QEMU must be compiled with --disable-coroutine-pool
                # to work around a suspected compiler bug.
                qemu_configure_flags += ['--disable-coroutine-pool']

        if version_greater_than(qemu_version, '2.4.0'):
            qemu_configure_flags += ['--disable-bzip2']

        if version_greater_than(qemu_version, '2.8.0'):
            qemu_configure_flags += ['--disable-gnutls',
                                     '--disable-nettle',
                                     '--disable-gcrypt',
                                     '--disable-roms',
                                     '--audio-drv-list=']

        qemu_configure_flags += ['--disable-docs']

        qemu_configure_flags += ['--extra-cflags=-fgnu89-inline']

        # disable IASL builds
        qemu_configure_flags += ['--iasl=false']

        # Guess target to build
        qemu_target = None
        if options.target.startswith('ppc64'):
            qemu_target = ['ppc64-softmmu']
        elif options.target.startswith('ppc') or \
                options.target.startswith('e500v2') or \
                options.target.startswith('p55'):
            qemu_target = ['ppc-softmmu']
        elif options.target.startswith('leon') or \
                options.target.startswith('erc32'):
            qemu_target = ['sparc-softmmu']
        elif options.target.startswith('x86-'):
            qemu_target = ['i386-softmmu']
        elif options.target.startswith('x86_64'):
            qemu_target = ['x86_64-softmmu']
        elif options.target.startswith('arm'):
            qemu_target = ['arm-softmmu', 'armeb-softmmu']
        elif options.target.startswith('aarch64'):
            qemu_target = ['aarch64-softmmu']
        if qemu_target is None:
            parser.error('cannot guess qemu target')

        # Add some default configure options
        qemu_configure_flags += ['--disable-sdl',
                                 '--disable-virtfs',
                                 '--disable-curl',
                                 '--disable-curses',
                                 '--disable-kvm',
                                 '--disable-attr',
                                 '--disable-uuid',
                                 '--target-list=' + ','.join(qemu_target),
                                 '--with-pkgversion=AdaCore-%s-%s' %
                                 (qemu_version, qemu_version_date)]

        if len(qemu_target) != len(qemu_bin):
            parser.error('invalid targets and binaries list (%s, %s)' %
                         (str(qemu_target), str(qemu_bin)))

        for i in range(len(qemu_bin)):
            qemu_bin[i] = 'qemu/%s/%s ' % (qemu_target[i], qemu_bin[i])

        print qemu_bin
    else:
        # We are picking a binary version of qemu so check its existence
        for i in range(len(qemu_bin)):
            qemu_bin[i] = locate_exec(qemu_bin[i]).replace('\\', '/')
            if len(qemu_bin[i]) == 0:
                parser.error('cannot locate qemu executable')

    conf.add_value('qemu_configure_flags',
                   " ".join(qemu_configure_flags),
                   "Configure flags for QEMU build")
    conf.add_value('qemu_bin', ' '.join(qemu_bin), "QEMU executable")
    conf.add_value('build_qemu', build_qemu, "Build QEMU from source")

    # Perform substitution
    sub('./Makefile', conf.values)

    # Generate driver_contants.ads to replace dummy version
    fd = open('gnatemu/src/driver_constants.ads', 'w')
    fd.write("""
package Driver_Constants is

   Version : constant String := "%s";
   Version_Date : constant String := "%s";

end Driver_Constants;
""" % (version, version_date))
    fd.close()
