# -*- coding:utf-8 -*-

"""
This file is part of OpenSesame.

OpenSesame is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

OpenSesame is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""
from libopensesame.py3compat import *
import re
from libopensesame.oslogging import oslogger
from pyqode.core import api
from libqtopensesame.misc.config import cfg
from libqtopensesame.misc.translate import translation_context
_ = translation_context(u'pyqode_manager', category=u'extension')

THRESHOLD = 500


class AutodetectIndentationMode(api.Mode):

    """Automatically sets indentation based on editor contents."""
    def on_install(self, editor):

        super(AutodetectIndentationMode, self).on_install(editor)
        self.editor.new_text_set.connect(self._autodetect_indentation)
        self._autodetect_indentation()

    def _autodetect_indentation(self):

        if cfg.pyqode_indentation == 'spaces':
            self._set_space_indentation(cfg.pyqode_tab_length)
            return
        if cfg.pyqode_indentation == 'tabs':
            self._set_tab_indentation()
            return
        code = self.editor.toPlainText().replace(u'\u2029', u'\n')
        match_tabs = re.findall(u'((?<=\n)\t+)|(\A\t+)', code)
        tab_length = self._guess_indentation_width(code)
        if tab_length == 0:
            match_spaces = []
        else:
            match_spaces = re.findall(
                u'((?<=\n){indent}+)|(\A{indent}+)'.format(
                    indent=u' ' * tab_length
                ),
                code
            )
        if len(match_tabs) > len(match_spaces):
            oslogger.debug(u'detected tab-based indentation')
            self._set_tab_indentation()
        else:
            oslogger.debug(
                u'detected space-based indentation (width={})'.format(
                    tab_length
                )
            )
            self._set_space_indentation(tab_length)

    def _set_tab_indentation(self):

        self.editor.use_spaces_instead_of_tabs = False

    def _set_space_indentation(self, tab_length):

        self.editor.use_spaces_instead_of_tabs = True
        self.editor.tab_length = tab_length

    def _guess_indentation_width(self, code):

        i2 = i3 = i4 = 0
        for line in code.splitlines():
            n_indent = len(line) - len(line.lstrip(u' '))
            if not n_indent:
                continue
            if not n_indent % 4:
                i4 += 1
                i3 -= 1
            elif not n_indent % 2:
                i2 += 1
                i4 -= 1
                i3 -= 1
            elif not n_indent % 3:
                i3 += 1
                i2 -= 1
                i4 -= 1
            if i4 - i2 > THRESHOLD and i4 - i3 > THRESHOLD:
                return 4
            if i3 - i2 > THRESHOLD and i3 - i4 > THRESHOLD:
                return 3
            if i2 - i3 > THRESHOLD and i2 - i4 > THRESHOLD:
                return 2
        if i4 > max(i2, i3):
            return 4
        if i3 > max(i2, i4):
            return 3
        if i2 > max(i4, i3):
            return 2
        return cfg.pyqode_tab_length
