# -*- coding: utf-8 -*-
import os
from pyqode.core import api, icons
from pyqode.qt import QtGui, QtCore, QtWidgets


class CommentsMode(api.Mode):
    """ Comments/uncomments a set of lines using Ctrl+/.
    """
    def __init__(self):
        super(CommentsMode, self).__init__()
        self.action = QtWidgets.QAction("Comment/Uncomment", self.editor)
        self.action.setShortcut("Ctrl+/")
        icon = icons.icon(qta_name='fa.comment')
        if icon:
            self.action.setIcon(icon)

    def on_state_changed(self, state):
        """
        Called when the mode is activated/deactivated
        """
        if state:
            self.action.triggered.connect(self.comment)
            self.editor.add_action(self.action)
            if 'pyqt5' in os.environ['QT_API'].lower():
                self.editor.key_pressed.connect(self.on_key_pressed)
        else:
            self.editor.remove_action(self.action)
            self.action.triggered.disconnect(self.comment)
            if 'pyqt5' in os.environ['QT_API'].lower():
                self.editor.key_pressed.disconnect(self.on_key_pressed)

    def on_key_pressed(self, key_event):
        ctrl = (key_event.modifiers() & QtCore.Qt.ControlModifier ==
                QtCore.Qt.ControlModifier)
        if key_event.key() == QtCore.Qt.Key_Slash and ctrl:
            self.comment()
            key_event.accept()

    def check_selection(self, cursor):
        sel_start = cursor.selectionStart()
        sel_end = cursor.selectionEnd()
        reversed_selection = cursor.position() == sel_start
        # were there any selected lines? If not select the current line
        has_selection = True
        if not cursor.hasSelection():
            cursor.select(QtGui.QTextCursor.LineUnderCursor)
            has_selection = False

        return has_selection, reversed_selection, sel_end, sel_start

    def comment(self):
        """
        Comments/Uncomments the selected lines or the current lines if there
        is no selection.
        """
        cursor = self.editor.textCursor()
        # make comment/uncomment a single operation for the undo stack
        cursor.beginEditBlock()

        # did the user do a reversed selection (from _bottom to _top)?
        has_sel, reversed_sel, sel_end, sel_start = self.check_selection(
            cursor)
        # get selected lines
        lines = cursor.selection().toPlainText().splitlines()
        nb_lines = len(lines)
        # move to first line
        cursor.setPosition(sel_start)
        # we uncomment if all lines were commented, otherwise we comment all
        # lines in selection
        comment = False
        for i in range(nb_lines):
            cursor.movePosition(QtGui.QTextCursor.StartOfLine)
            cursor.movePosition(QtGui.QTextCursor.EndOfLine, cursor.KeepAnchor)
            line = cursor.selectedText().lstrip()
            if not len(line.strip()):
                # skips empty lines
                continue
            indent = len(cursor.selectedText()) - len(line)
            if not line.startswith("# "):
                comment = True
                break
            # next line
            cursor.movePosition(QtGui.QTextCursor.EndOfLine)
            cursor.setPosition(cursor.position() + 1)
        cursor.setPosition(sel_start)
        l = 2  # len('# ') == 2
        performed = 0
        for i in range(nb_lines):
            cursor.movePosition(QtGui.QTextCursor.StartOfLine)
            cursor.movePosition(QtGui.QTextCursor.EndOfLine, cursor.KeepAnchor)
            line = cursor.selectedText().lstrip()
            if line != "":
                cursor.movePosition(QtGui.QTextCursor.StartOfLine)
                # Uncomment
                if not comment:
                    cursor.setPosition(cursor.position() + indent)
                    cursor.movePosition(cursor.Right, cursor.KeepAnchor, 2)
                    cursor.insertText("")
                    if i == 0:
                        sel_start -= l
                    sel_end -= l
                # comment
                else:
                    cursor.movePosition(QtGui.QTextCursor.StartOfLine)
                    cursor.setPosition(cursor.position() + indent)
                    cursor.insertText("# ")
                    if i == 0:
                        sel_start += l
                    sel_end += l
            performed += 1
            # next line
            cursor.movePosition(QtGui.QTextCursor.EndOfLine)
            if not cursor.atEnd():
                cursor.setPosition(cursor.position() + 1)
        cursor.endEditBlock()
        if has_sel:
            cursor.setPosition(sel_start)
            cursor.setPosition(sel_end, QtGui.QTextCursor.KeepAnchor)
        else:
            if not cursor.atEnd():
                if performed:
                    cursor.setPosition(sel_start + (l if not comment else -l))
                cursor.movePosition(cursor.Down, cursor.MoveAnchor, 1)
        self.editor.setTextCursor(cursor)
