"""
For internal use only.
"""
from __future__ import unicode_literals

from prompt_toolkit.mouse_events import MouseEventType
import re

__all__ = (
    'has_unclosed_brackets',
    'get_jedi_script_from_document',
    'document_is_multiline_python',
)


def has_unclosed_brackets(text):
    """
    Starting at the end of the string. If we find an opening bracket
    for which we didn't had a closing one yet, return True.
    """
    stack = []

    # Ignore braces inside strings
    text = re.sub(r'''('[^']*'|"[^"]*")''', '', text)  # XXX: handle escaped quotes.!

    for c in reversed(text):
        if c in '])}':
            stack.append(c)

        elif c in '[({':
            if stack:
                if ((c == '[' and stack[-1] == ']') or
                        (c == '{' and stack[-1] == '}') or
                        (c == '(' and stack[-1] == ')')):
                    stack.pop()
            else:
                # Opening bracket for which we didn't had a closing one.
                return True

    return False


def get_jedi_script_from_document(document, locals, globals):
    import jedi  # We keep this import in-line, to improve start-up time.
                 # Importing Jedi is 'slow'.

    try:
        return jedi.Interpreter(
            document.text,
            column=document.cursor_position_col,
            line=document.cursor_position_row + 1,
            path='input-text',
            namespaces=[locals, globals])
    except ValueError:
        # Invalid cursor position.
        # ValueError('`column` parameter is not in a valid range.')
        return None
    except AttributeError:
        # Workaround for #65: https://github.com/jonathanslenders/python-prompt-toolkit/issues/65
        # See also: https://github.com/davidhalter/jedi/issues/508
        return None
    except IndexError:
        # Workaround Jedi issue #514: for https://github.com/davidhalter/jedi/issues/514
        return None
    except KeyError:
        # Workaroud for a crash when the input is "u'", the start of a unicode string.
        return None
    except Exception:
        # Workaround for: https://github.com/jonathanslenders/ptpython/issues/91
        return None


_multiline_string_delims = re.compile('''[']{3}|["]{3}''')


def document_is_multiline_python(document):
    """
    Determine whether this is a multiline Python document.
    """
    def ends_in_multiline_string():
        """
        ``True`` if we're inside a multiline string at the end of the text.
        """
        delims = _multiline_string_delims.findall(document.text)
        opening = None
        for delim in delims:
            if opening is None:
                opening = delim
            elif delim == opening:
                opening = None
        return bool(opening)

    if '\n' in document.text or ends_in_multiline_string():
        return True

    def line_ends_with_colon():
        return document.current_line.rstrip()[-1:] == ':'

    # If we just typed a colon, or still have open brackets, always insert a real newline.
    if line_ends_with_colon() or \
            (document.is_cursor_at_the_end and
             has_unclosed_brackets(document.text_before_cursor)) or \
            document.text.startswith('@'):
        return True

    # If the character before the cursor is a backslash (line continuation
    # char), insert a new line.
    elif document.text_before_cursor[-1:] == '\\':
        return True

    return False


def if_mousedown(handler):
    """
    Decorator for mouse handlers.
    Only handle event when the user pressed mouse down.

    (When applied to a token list. Scroll events will bubble up and are handled
    by the Window.)
    """
    def handle_if_mouse_down(mouse_event):
        if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
            return handler(mouse_event)
        else:
            return NotImplemented
    return handle_if_mouse_down
