# -*- 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 indentation guide panel.
"""

# Third party imports
from qtpy.QtCore import Qt
from qtpy.QtGui import QPainter, QColor

# Local imports
from spyder.plugins.editor.api.panel import Panel


class IndentationGuide(Panel):
    """Indentation guides to easy identify nested blocks."""

    # --- Qt Overrides
    # -----------------------------------------------------------------
    def __init__(self):
        """Initialize IndentationGuide panel.
        i_width(int): identation width in characters.
        """
        Panel.__init__(self)
        self.color = Qt.darkGray
        self.i_width = 4
        self.bar_offset = 0

    def on_install(self, editor):
        """Manages install setup of the pane."""
        super().on_install(editor)
        horizontal_scrollbar = editor.horizontalScrollBar()
        horizontal_scrollbar.valueChanged.connect(self.update_bar_position)
        horizontal_scrollbar.sliderReleased.connect(self.update)

    def update_bar_position(self, value):
        self.bar_offset = value

    def sizeHint(self):
        """Override Qt method."""
        return self.size()

    def paintEvent(self, event):
        """
        Overriden Qt method.

        Paint indent guides.
        """
        # Set painter
        painter = QPainter(self)
        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        # Compute offset
        offset = (self.editor.document().documentMargin() +
                  self.editor.contentOffset().x())

        # Folding info
        folding_panel = self.editor.panels.get('FoldingPanel')
        folding_regions = folding_panel.folding_regions
        leading_whitespaces = self.editor.leading_whitespaces

        # Visible block numbers
        visible_blocks = self.editor.get_visible_block_numbers()

        # Paint lines
        for start_line in folding_regions:
            end_line = folding_regions[start_line]
            line_numbers = (start_line, end_line)

            if self.do_paint(visible_blocks, line_numbers):
                start_block = self.editor.document().findBlockByNumber(
                    start_line)
                end_block = self.editor.document().findBlockByNumber(
                    end_line - 1)

                content_offset = self.editor.contentOffset()
                top = int(self.editor.blockBoundingGeometry(
                    start_block).translated(content_offset).top())
                bottom = int(self.editor.blockBoundingGeometry(
                    end_block).translated(content_offset).bottom())

                total_whitespace = leading_whitespaces.get(
                    max(start_line - 1, 0))
                end_whitespace = leading_whitespaces.get(end_line - 1)

                if end_whitespace and end_whitespace != total_whitespace:
                    font_metrics = self.editor.fontMetrics()
                    x = int(font_metrics.width(total_whitespace * '9') +
                            self.bar_offset + offset)
                    painter.drawLine(x, top, x, bottom)

    # --- Other methods
    # -----------------------------------------------------------------
    def set_enabled(self, state):
        """Toggle edge line visibility."""
        self._enabled = state
        self.setVisible(state)

        # We need to request folding when toggling state so the lines
        # are computed when handling the folding response.
        self.editor.request_folding()

    def update_color(self):
        """Set color using syntax highlighter color for comments."""
        self.color = self.editor.highlighter.get_color_name('comment')

    def set_indentation_width(self, indentation_width):
        """Set indentation width to be used to draw indent guides."""
        self.i_width = indentation_width

    def do_paint(self, visible_blocks, line_numbers):
        """
        Decide if we need to paint an indent guide according to the
        visible region.
        """
        # Line numbers for the visible region.
        first_visible_line = visible_blocks[0] + 1
        last_visible_line = visible_blocks[1] + 1

        # Line numbers for the indent guide.
        start_line = line_numbers[0]
        end_line = line_numbers[1]

        # Guide starts before the visible region and ends inside it.
        if (start_line < first_visible_line and
                (first_visible_line <= end_line <= last_visible_line)):
            return True

        # Guide starts before the visible region and ends after it.
        if start_line <= first_visible_line and end_line >= last_visible_line:
            return True

        # Guide starts inside the visible region and ends after it.
        if ((first_visible_line <= start_line <= last_visible_line) and
                end_line > last_visible_line):
            return True

        # Guide starts and ends inside the visible region.
        if ((first_visible_line <= start_line <= last_visible_line) and
                (first_visible_line <= end_line <= last_visible_line)):
            return True

        # If none of those cases are true, we don't need to paint this guide.
        return False
