import os
import sys
import shlex
import shutil
import argparse
import platform
import subprocess
import uuid


ROOTDIR = os.path.abspath(os.path.dirname(__file__))


if os.name == 'nt':
    import ctypes
    from ctypes import wintypes
    _GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
    _GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD]
    _GetShortPathNameW.restype = wintypes.DWORD

def win32_get_short_path_name(long_name):
    """
    Gets the short path name of a given long path.
    http://stackoverflow.com/a/23598461/200291
    """
    output_buf_size = 0
    while True:
        output_buf = ctypes.create_unicode_buffer(output_buf_size)
        needed = _GetShortPathNameW(long_name, output_buf, output_buf_size)
        if output_buf_size >= needed:
            return output_buf.value
        else:
            output_buf_size = needed


def get_wine_shortpath(winecmd, wine_paths):
    seen = set()
    wine_paths += [p for p in wine_paths if not (p in seen or seen.add(p))]

    getShortPathScript = '%s.bat' % str(uuid.uuid4()).lower()[:5]
    with open(getShortPathScript, mode='w') as f:
        f.write("@ECHO OFF\nfor %%x in (%*) do (\n echo|set /p=;%~sx\n)\n")
        f.flush()
    try:
        with open(os.devnull, 'w') as stderr:
            wine_path = subprocess.check_output(
                winecmd +
                ['cmd', '/C', getShortPathScript] + wine_paths,
                stderr=stderr).decode('utf-8')
    except subprocess.CalledProcessError as e:
        print("Could not get short paths: %s" % e)
        wine_path = ';'.join(wine_paths)
    finally:
        os.remove(getShortPathScript)
    if len(wine_path) > 2048:
        raise AssertionError('WINEPATH size {} > 2048'
                                ' this will cause random failure.'.format(
                                    len(wine_path)))
    return wine_path


class Colors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'

    force_disable = False

    def _windows_ansi():
        from ctypes import windll, byref
        from ctypes.wintypes import DWORD

        kernel = windll.kernel32
        stdout = kernel.GetStdHandle(-11)
        mode = DWORD()
        if not kernel.GetConsoleMode(stdout, byref(mode)):
            return False
        # Try setting ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
        # If that fails (returns 0), we disable colors
        return kernel.SetConsoleMode(stdout, mode.value | 0x4) or os.environ.get('ANSICON')

    @classmethod
    def can_enable(cls):
        if not os.isatty(sys.stdout.fileno()):
            return False
        if platform.system().lower() == 'windows':
            return cls._windows_ansi()
        return os.environ.get('TERM') != 'dumb'

    @classmethod
    def disable(cls):
        cls.HEADER = ''
        cls.OKBLUE = ''
        cls.OKGREEN = ''
        cls.WARNING = ''
        cls.FAIL = ''
        cls.ENDC = ''

    @classmethod
    def enable(cls):
        if cls.force_disable:
            return

        cls.HEADER = '\033[95m'
        cls.OKBLUE = '\033[94m'
        cls.OKGREEN = '\033[92m'
        cls.WARNING = '\033[93m'
        cls.FAIL = '\033[91m'
        cls.ENDC = '\033[0m'



def git(*args, repository_path='.', fatal=True):
    try:
        ret = subprocess.check_output(["git"] + list(args), cwd=repository_path,
                                      stdin=subprocess.DEVNULL,
                                      stderr=subprocess.STDOUT).decode()
    except subprocess.CalledProcessError as e:
        if fatal:
            raise e
        print("Non-fatal error running git {}:\n{}".format(' '.join(args), e))
        return None
    return ret

def accept_command(commands):
    """Search @commands and returns the first found absolute path."""
    for command in commands:
        command = shutil.which(command)
        if command:
            return command
    return None

def get_meson():
    meson = os.path.join(ROOTDIR, 'meson', 'meson.py')
    if os.path.exists(meson):
        return [sys.executable, meson]

    mesonintrospect = os.environ.get('MESONINTROSPECT', '')
    for comp in shlex.split (mesonintrospect):
        # mesonintrospect might look like "/usr/bin/python /somewhere/meson introspect",
        # let's not get tricked
        if 'python' in os.path.basename (comp):
            continue
        if os.path.exists(comp):
            if comp.endswith('.py'):
                return [sys.executable, comp]
            else:
                return [comp]

    meson = accept_command(['meson.py'])
    if meson:
        return [sys.executable, meson]
    meson = accept_command(['meson'])
    if meson:
        return [meson]
    raise RuntimeError('Could not find Meson')