# -*- coding: utf-8 -*-

import re

_REGEX = re.compile('^(?P<major>[0-9]+)'
                    '\.(?P<minor>[0-9]+)'
                    '(\.(?P<patch>[0-9]+))?'
                    '(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
                    '(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')

if 'cmp' not in __builtins__:
    cmp = lambda a,b: (a > b) - (a < b)

def parse(version):
    """
    Parse version to major, minor, patch, pre-release, build parts.
    """
    match = _REGEX.match(version)
    if match is None:
        raise ValueError('%s is not valid SemVer string' % version)

    verinfo = match.groupdict()

    verinfo['major'] = int(verinfo['major'])
    verinfo['minor'] = int(verinfo['minor'])
    verinfo['patch'] = int(verinfo['patch'] or '0')

    return verinfo


def compare(ver1, ver2):
    def nat_cmp(a, b):
        a, b = a or '', b or ''
        convert = lambda text: text.isdigit() and int(text) or text.lower()
        alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
        return cmp(alphanum_key(a), alphanum_key(b))

    def compare_by_keys(d1, d2):
        for key in ['major', 'minor', 'patch']:
            v = cmp(d1.get(key), d2.get(key))
            if v:
                return v
        rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
        build1, build2 = d1.get('build'), d2.get('build')
        rccmp = nat_cmp(rc1, rc2)
        buildcmp = nat_cmp(build1, build2)
        if not (rc1 or rc2):
            return buildcmp
        elif not rc1:
            return 1
        elif not rc2:
            return -1
        return rccmp or buildcmp or 0

    v1, v2 = parse(ver1), parse(ver2)

    return compare_by_keys(v1, v2)


def match(version, match_expr):
    prefix = match_expr[:2]
    if prefix in ('>=', '<=', '=='):
        match_version = match_expr[2:]
    elif prefix and prefix[0] in ('>', '<', '='):
        prefix = prefix[0]
        match_version = match_expr[1:]
    else:
        raise ValueError("match_expr parameter should be in format <op><ver>, "
                         "where <op> is one of ['<', '>', '==', '<=', '>=']. "
                         "You provided: %r" % match_expr)

    possibilities_dict = {
        '>': (1,),
        '<': (-1,),
        '==': (0,),
        '>=': (0, 1),
        '<=': (-1, 0)
    }

    possibilities = possibilities_dict[prefix]
    cmp_res = compare(version, match_version)

    return cmp_res in possibilities
