import vim, re
import heapq

_escape = dict((c , "\\" + c) for c in ['^','$','.','{','}','(',')','[',']','\\','/','+'])

def CtrlPPyMatch():
    items = vim.eval('a:items')
    astr = vim.eval('a:str')
    lowAstr = astr.lower()
    limit = int(vim.eval('a:limit'))
    mmode = vim.eval('a:mmode')
    aregex = int(vim.eval('a:regex'))
    spath = vim.eval('a:ispath')
    crfile = vim.eval('a:crfile')

    if not vim.eval('exists("g:ctrlp_match_current_file")') and ispath and crfile:
        items.remove(crfile)

    rez = vim.eval('s:rez')


    regex = ''
    if aregex == 1:
        regex = astr
    else:
        # Escape all of the characters as necessary
        escaped = [_escape.get(c, c) for c in lowAstr]

        # If the string is longer that one character, append a mismatch
        # expression to each character (except the last).
        if len(lowAstr) > 1:
            mismatch = ["[^" + c + "]*" for c in escaped[:-1]]
            regex = ''.join([c for pair in zip(escaped[:-1], mismatch) for c in pair])

        # Append the last character in the string to the regex
        regex += escaped[-1]
    # because this IGNORECASE flag is extremely expensive we are converting everything to lower case
    # see https://github.com/FelikZ/ctrlp-py-matcher/issues/29
    regex = regex.lower()

    res = []
    prog = re.compile(regex)

    def filename_score(line):
        # get filename via reverse find to improve performance
        slashPos = line.rfind('/')

        if slashPos != -1:
            line = line[slashPos + 1:]

        lineLower = line.lower()
        result = prog.search(lineLower)
        if result:
            score = result.end() - result.start() + 1
            score = score + ( len(lineLower) + 1 ) / 100.0
            score = score + ( len(line) + 1 ) / 1000.0
            return 1000.0 / score

        return 0

    def path_score(line):
        lineLower = line.lower()
        result = prog.search(lineLower)
        if result:
            score = result.end() - result.start() + 1
            score = score + ( len(lineLower) + 1 ) / 100.0
            return 1000.0 / score

        return 0

    if mmode == 'filename-only':
        res = [(filename_score(line), line) for line in items]

    elif mmode == 'first-non-tab':
        res = [(path_score(line.split('\t')[0]), line) for line in items]

    elif mmode == 'until-last-tab':
        res = [(path_score(line.rsplit('\t')[0]), line) for line in items]

    else:
        res = [(path_score(line), line) for line in items]

    rez.extend([line for score, line in heapq.nlargest(limit, res) if score != 0])

    # Use double quoted vim strings and escape \
    vimrez = ['"' + line.replace('\\', '\\\\').replace('"', '\\"') + '"' for line in rez]

    vim.command("let s:regex = '%s'" % regex)
    vim.command('let s:rez = [%s]' % ','.join(vimrez))

