# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""This module contains the close quotes editor extension."""

from qtpy.QtGui import QTextCursor
from spyder.api.editorextension import EditorExtension


class CloseBracketsExtension(EditorExtension):
    """Editor Extension for insert brackets automatically."""
    BRACKETS_CHAR = ["(", ")", "{", "}", "[", "]"]
    BRACKETS_LEFT = BRACKETS_CHAR[::2]
    BRACKETS_RIGHT = BRACKETS_CHAR[1::2]
    BRACKETS_PAIR = {"(": "()", ")": "()",
                     "{": "{}", "}": "{}",
                     "[": "[]", "]": "[]"}

    def on_state_changed(self, state):
        """Connect/disconnect sig_key_pressed signal."""
        if state:
            self.editor.sig_key_pressed.connect(self._on_key_pressed)
        else:
            self.editor.sig_key_pressed.disconnect(self._on_key_pressed)

    def _on_key_pressed(self, event):
        if event.isAccepted():
            return

        # It is necessary to use here the text of the event and not the key
        # to avoid issues with international keyboards.
        # See spyder-ide/spyder#9749
        char = event.text()
        if char in self.BRACKETS_CHAR and self.enabled:
            self.editor.completion_widget.hide()
            self._autoinsert_brackets(char)
            event.accept()

    def unmatched_brackets_in_line(self, text, closing_brackets_type=None,
                                   autoinsert=False):
        """
        Checks if there is an unmatched brackets in the 'text'.

        The brackets type can be general or specified by closing_brackets_type
        (')', ']' or '}')
        """
        if closing_brackets_type is None:
            opening_brackets = self.BRACKETS_LEFT
            closing_brackets = self.BRACKETS_RIGHT
        else:
            closing_brackets = [closing_brackets_type]
            opening_brackets = [{')': '(', '}': '{',
                                 ']': '['}[closing_brackets_type]]
        block = self.editor.textCursor().block()
        line_pos = block.position()
        for pos, char in enumerate(text):
            if char in opening_brackets:
                match = self.editor.find_brace_match(line_pos+pos, char,
                                                     forward=True)
                if (match is None) or (match > line_pos+len(text)):
                    return True
            if char in closing_brackets:
                match = self.editor.find_brace_match(line_pos+pos, char,
                                                     forward=False)
                # Only validate match existence for autoinsert.
                # Having the missing bracket in a previous line is possible.
                # See spyder-ide/spyder#11217
                if (match is None) or (match < line_pos and not autoinsert):
                    return True
        return False

    def _autoinsert_brackets(self, char):
        """Control automatic insertation of brackets in various situations."""
        pair = self.BRACKETS_PAIR[char]

        cursor = self.editor.textCursor()
        trailing_text = self.editor.get_text('cursor', 'eol').strip()

        if self.editor.has_selected_text():
            text = self.editor.get_selected_text()
            self.editor.insert_text("{0}{1}{2}".format(pair[0], text, pair[1]))
            # Keep text selected, for inserting multiple brackets
            cursor.movePosition(QTextCursor.Left, QTextCursor.MoveAnchor, 1)
            cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
                                len(text))
            self.editor.setTextCursor(cursor)
        elif char in self.BRACKETS_LEFT:
            if (not trailing_text or
                    trailing_text[0] in self.BRACKETS_RIGHT or
                    trailing_text[0] in [',', ':', ';']):
                # Automatic insertion of brackets
                self.editor.insert_text(pair)
                cursor.movePosition(QTextCursor.PreviousCharacter)
                self.editor.setTextCursor(cursor)
            else:
                self.editor.insert_text(char)
            if char in self.editor.signature_completion_characters:
                self.editor.request_signature()
        elif char in self.BRACKETS_RIGHT:
            if (self.editor.next_char() == char and
                    not self.editor.textCursor().atBlockEnd() and
                    not self.unmatched_brackets_in_line(
                        cursor.block().text(), char, autoinsert=True)):
                # Overwrite an existing brackets if all in line are matched
                cursor.movePosition(QTextCursor.NextCharacter,
                                    QTextCursor.KeepAnchor, 1)
                cursor.clearSelection()
                self.editor.setTextCursor(cursor)
            else:
                self.editor.insert_text(char)
