# -*- coding: utf-8 -*-
""" Contains the AutoCompleteMode """
import logging
from pyqode.qt import QtCore, QtGui
from pyqode.core.api import TextHelper
from pyqode.core.api.mode import Mode


class AutoCompleteMode(Mode):
    """ Automatically complete quotes and parentheses

    Generic auto complete mode that automatically completes the following
    symbols:

        - " -> "
        - ' -> '
        - ( -> )
        - [ -> ]
        - { -> }
    """
    #: Auto complete mapping, maps input key with completion text.
    MAPPING = {'"': '"', "'": "'", "(": ")", "{": "}", "[": "]"}
    #: The format to use for each symbol in mapping when there is a selection
    SELECTED_QUOTES_FORMATS = {key: '%s%s%s' for key in MAPPING.keys()}
    #: The format to use for each symbol in mapping when there is no selection
    QUOTES_FORMATS = {key: '%s' for key in MAPPING.keys()}

    def __init__(self):
        super(AutoCompleteMode, self).__init__()
        self.logger = logging.getLogger(__name__)
        self._ignore_post = False

    def on_state_changed(self, state):
        if state:
            self.editor.post_key_pressed.connect(self._on_post_key_pressed)
            self.editor.key_pressed.connect(self._on_key_pressed)
        else:
            self.editor.post_key_pressed.disconnect(self._on_post_key_pressed)
            self.editor.key_pressed.disconnect(self._on_key_pressed)

    def _on_post_key_pressed(self, event):
        if not event.isAccepted() and not self._ignore_post:
            txt = event.text()
            trav = self.editor.textCursor()
            assert isinstance(trav, QtGui.QTextCursor)
            trav.movePosition(trav.Left, trav.MoveAnchor, 2)
            literal = TextHelper(self.editor).is_comment_or_string(trav)
            if not literal:
                next_char = TextHelper(self.editor).get_right_character()
                if txt in self.MAPPING:
                    to_insert = self.MAPPING[txt]
                    if (not next_char or next_char in self.MAPPING.keys() or
                            next_char in self.MAPPING.values() or
                            next_char.isspace()):
                        TextHelper(self.editor).insert_text(
                            self.QUOTES_FORMATS[txt] % to_insert)
        self._ignore_post = False

    def _on_key_pressed(self, event):
        txt = event.text()
        cursor = self.editor.textCursor()
        from pyqode.qt import QtGui
        assert isinstance(cursor, QtGui.QTextCursor)
        if cursor.hasSelection():
            # quoting of selected text
            if event.text() in self.MAPPING.keys():
                first = event.text()
                last = self.MAPPING[event.text()]
                cursor.insertText(
                    self.SELECTED_QUOTES_FORMATS[event.text()] % (
                        first, cursor.selectedText(), last))
                self.editor.setTextCursor(cursor)
                event.accept()
            else:
                self._ignore_post = True
            return
        next_char = TextHelper(self.editor).get_right_character()
        self.logger.debug('next char: %s', next_char)
        ignore = False
        if event.key() == QtCore.Qt.Key_Backspace:
            # get the character that will get deleted
            tc = self.editor.textCursor()
            pos = tc.position()
            tc.movePosition(tc.Left)
            tc.movePosition(tc.Right, tc.KeepAnchor)
            del_char = tc.selectedText()
            if del_char in self.MAPPING and \
                    self.MAPPING[del_char] == next_char:
                tc.beginEditBlock()
                tc.movePosition(tc.Right, tc.KeepAnchor)
                tc.insertText('')
                tc.setPosition(pos - 2)
                tc.endEditBlock()
                self.editor.setTextCursor(tc)
                ignore = True
        elif txt and next_char == txt and next_char in self.MAPPING:
            ignore = True
        elif event.text() == ')' or event.text() == ']' or event.text() == '}':
            # if typing the same symbol twice, the symbol should not be written
            # and the cursor moved just after the char
            # e.g. if you type ) just before ), the cursor will just move after
            # the existing )
            if next_char == event.text():
                ignore = True
        if ignore:
            event.accept()
            TextHelper(self.editor).clear_selection()
            TextHelper(self.editor).move_right()
