import re
import regex
from point import Point
from render import HighlightRegion

BG         = 'black'
SELECTED   = 'magenta'
UNSELECTED = 'yellow'

class IllegalPatternError(Exception):
    pass

def escape_literal(s):
    return re.escape(s)

def find_ranges(r, w, start=None, end=None):
    if not w.buffer.lines:
        return []

    if start is None:
        (x, y) = (0, 0)
    else:
        (x, y) = start.xy()
    if end is None:
        (x2, y2) = (len(w.buffer.lines[-1]), len(w.buffer.lines) - 1)
    else:
        (x2, y2) = end.xy()

    ranges = []
    while y <= y2:
        if y == y2:
            limit = x2
        else:
            limit = len(w.buffer.lines[y])
        for m in r.finditer(w.buffer.lines[y], x, limit):
            if len(m.group(0)) == 0:
                raise IllegalPatternError("zero-width match found")
            p1, p2 = Point(m.start(), y), Point(m.end(), y)
            hr = HighlightRegion(w, p1, p2, BG, UNSELECTED, match=m, name='search')
            ranges.append(hr)
        x = 0
        y += 1
    return ranges

def find(r, w, move=False, direction='next', start=None, end=None):
    app     = w.application
    c       = w.logical_cursor()
    newc    = None
    ranges  = find_ranges(r, w, start, end)
    indices = range(0, len(ranges))
    (x, y) = c.xy()
    if move:
        offset = 1
    else:
        offset = 0
    if direction == 'next':
        limit = Point(x - 1 + offset, y)
    elif direction == 'previous':
        limit  = Point(x + 1 - offset, y)
        for hr in app.highlighted_ranges:
            (wz, p1, p2, fg, bg) = hr
            if p1 == c:
                limit = Point(x + 1 + p2.x - p1.x - 2*offset + 1, y)
                break
        indices.reverse()
    else:
        raise Exception, 'blech'
    for i in indices:
        if (direction == 'next' and ranges[i].p1 > limit or
            direction == 'previous' and ranges[i].p2 < limit):
            ranges[i].bg = SELECTED
            newc = (ranges[i].p1, ranges[i].p2, ranges[i].match)
            break
    if newc:
        w.goto(newc[0])
    elif ranges:
        i = 0
        if direction == 'next':
            i = -1
        ranges[i].bg = SELECTED
        newc         = (ranges[i].p1, ranges[i].p2, ranges[i].match)
        
    app.clear_highlighted_ranges('search')
    for hr in ranges:
        if hr.p1 < w.first:
            continue
        elif hr.p2 > w.last:
            break
        app.add_highlighted_range(hr)
    return newc

def find_previous(r, w, move=False, start=None, end=None):
    return find(r, w, move, 'previous', start, end)
def find_next(r, w, move=False, start=None, end=None):
    return find(r, w, move, 'next', start, end)