# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2016 Continuum Analytics, Inc.
#
# May be copied and distributed freely only as part of an Anaconda or
# Miniconda installation.
# -----------------------------------------------------------------------------
"""Helper widgets."""

from __future__ import (absolute_import, division, print_function,
                        with_statement)

# Third party imports
from qtpy import PYQT4
from qtpy.compat import getexistingdirectory, getopenfilename
from qtpy.QtCore import Qt, QRegExp, QSize, Signal
from qtpy.QtGui import QRegExpValidator, QIcon
from qtpy.QtWidgets import (QCheckBox, QHBoxLayout, QLabel, QLineEdit,
                            QMessageBox, QPushButton, QSpacerItem,
                            QVBoxLayout, QWidget,
                            )


class MessageCheckBox(QMessageBox):
    """A QMessageBox derived widget that includes a QCheckBox."""

    def __init__(self, *args, **kwargs):
        """A QMessageBox derived widget that includes a QCheckBox."""
        super(MessageCheckBox, self).__init__(*args, **kwargs)

        self._checkbox = QCheckBox()

        # Set layout to include checkbox
        size = 9
        check_layout = QVBoxLayout()
        check_layout_h = QHBoxLayout()
        check_layout.addItem(QSpacerItem(size, size))
        check_layout_h.addStretch()
        check_layout_h.addWidget(self._checkbox, 1, Qt.AlignRight)
        check_layout.addLayout(check_layout_h)
        check_layout.addItem(QSpacerItem(size, size))

        # Access the Layout of the MessageBox to add the Checkbox
        layout = self.layout()

        if PYQT4:
            grid_position = 1
        else:
            grid_position = 2

        layout.addLayout(check_layout, 1, grid_position)

    # --- Public API
    # Methods to access the checkbox
    def is_checked(self):
        """Return True if checkbox is checked."""
        return self._checkbox.isChecked()

    def set_checked(self, value):
        """Set the checked status of checkbox."""
        return self._checkbox.setChecked(value)

    def set_check_visible(self, value):
        """Set checkbox visibility."""
        self._checkbox.setVisible(value)

    def is_check_visible(self):
        """Retun True if checkbox is visible."""
        self._checkbox.isVisible()

    def checkbox_text(self):
        """Return the checked text."""
        self._checkbox.text()

    def set_checkbox_text(self, text):
        """Set the checked text."""
        self._checkbox.setText(text)

    @staticmethod
    def _boxcreator(parent, title, text, buttons=QMessageBox.Ok,
                    defaultButton=QMessageBox.NoButton, checkbox_text='',
                    icon=None):
        """Box creator helper."""
        widget = MessageCheckBox(icon, title, text, buttons=buttons,
                                 parent=parent)
        widget.set_checkbox_text(checkbox_text)
        return widget

    @staticmethod
    def warning(*args, **kwargs):
        """Override Qt method."""
        kwargs['icon'] = QMessageBox.Warning
        return MessageCheckBox._boxcreator(*args, **kwargs)

    @staticmethod
    def critical(*args, **kwargs):
        """Override Qt method."""
        kwargs['icon'] = QMessageBox.Critical
        return MessageCheckBox._boxcreator(*args, **kwargs)

    @staticmethod
    def information(*args, **kwargs):
        """Override Qt method."""
        kwargs['icon'] = QMessageBox.Information
        return MessageCheckBox._boxcreator(*args, **kwargs)

    @staticmethod
    def question(*args, **kwargs):
        """Override Qt method."""
        kwargs['icon'] = QMessageBox.Question
        return MessageCheckBox._boxcreator(*args, **kwargs)


class EditableLineEdit(QWidget):
    """Editable line edit with button to start editing."""

    sig_text_changed = Signal(object, object)  # old_text, new_text

    def __init__(self, title, text, regex=None, allow_empty=False):
        """Editable line edit with button to start editing."""
        super(EditableLineEdit, self).__init__()
        self._label = QLabel(title)
        self._text = QLineEdit()
        self.button_edit = QPushButton()
        self.allow_empty = allow_empty
        self.regex = regex
        self.qregex = None

        self.button_edit.setIcon(QIcon())
        self._text.setText(text)

        layout = QVBoxLayout()
        layout.addWidget(self._label)

        layout_h = QHBoxLayout()
        layout_h.addWidget(self._text)
        layout_h.addWidget(self.button_edit)
        layout.addLayout(layout_h)

        self.setLayout(layout)
        self._text.setDisabled(True)

        self.button_edit.clicked.connect(self.edit)

        self.last_text = self._text.text()
        self.set_regex(regex)

    def keyPressEvent(self, event):
        """Override Qt Method."""
        super(EditableLineEdit, self).keyPressEvent(event)
        key = event.key()
        if key in [Qt.Key_Enter, Qt.Key_Return]:
            self.check_text()
        elif key in [Qt.Key_Escape]:
            self._text.setText(self.last_text)
            self.check_text(escaped=True)

    # --- Public API
    # -------------------------------------------------------------------------
    def text(self):
        """Return current text."""
        return self._text.text()

    def set_text(self, text):
        """Set current text."""
        self._text.setText(text)

    def set_label_text(self, text):
        """Set label text."""
        self.label.setText(text)

    def set_regex(self, regex):
        """Set regular expression for text validation."""
        if regex:
            self.regex = regex
            self.qregex = QRegExp(regex)
            validator = QRegExpValidator(self.qregex)
            self._text.setValidator(validator)

    def check_text(self, escaped=False):
        """Check entered text is valid."""
        self._text.setDisabled(True)
        self.button_edit.setDisabled(False)
        new_text = self._text.text()

        if not self.allow_empty and len(new_text) == 0:
            self.edit()

        if self.last_text != new_text and not escaped:
            self.sig_text_changed.emit(self.last_text, new_text)
            self.last_text = new_text

    def edit(self):
        """Start editing text."""
        self._text.setDisabled(False)
        self.button_edit.setDisabled(True)
        self._text.setFocus()
        self._text.setCursorPosition(len(self._text.text()))
        self.last_text = self._text.text()


class EditablePathEdit(EditableLineEdit):
    """Editable LineEdit with edit button to search for a folder."""

    def __init__(self, title, text, basedir=None, fileselect=False,
                 caption='', filters='', selected_filter=''):
        """Editable LineEdit with edit button to search for a folder."""
        super(EditablePathEdit, self).__init__(title, text)
        self.basedir = basedir
        self.fileselect = fileselect
        self.filters = filters
        self.selected_filter = selected_filter
        self.caption = caption

    def set_directory(self, basedir):
        """Set current directory."""
        self.basedir = basedir

    def edit(self):
        """Start editing."""
        if self.fileselect:
            path, filter_ = getopenfilename(
                basedir=self.basedir,
                caption=self.caption,
                filters=self.filters,
                selectedfilter=self.selected_filter)
        else:
            path = getexistingdirectory(basedir=self.basedir,
                                        caption=self.caption)

        if path:
            self._text.setText(path)
            if path != self.last_text:
                self.sig_text_changed.emit(self.last_text, path)
            self.last_text = self._text.text()


class ButtonSearch(QPushButton):
    """Button used for CSS styling."""

    pass


class LineEditSearch(QLineEdit):
    """Lineedit search widget with clear button."""

    def __init__(self, *args, **kwargs):
        """Lineedit search widget with clear button."""
        super(LineEditSearch, self).__init__(*args, **kwargs)
        self._empty = True
        self._show_icons = False
        self.button_icon = ButtonSearch()

        self.button_icon.setDefault(True)
        self.button_icon.setFocusPolicy(Qt.NoFocus)

        layout = QHBoxLayout()
        layout.addWidget(self.button_icon, 0, Qt.AlignRight)
        layout.setSpacing(0)
        layout.addSpacing(2)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        # Signals
        self.textEdited.connect(self.update_box)
        self.button_icon.clicked.connect(self.clear_text)

        self.update_box(None)
        self.set_icon_size(16, 16)
        self.setTabOrder(self, self.button_icon)

    def set_icon_size(self, width, height):
        """Set clear button icon size."""
        self.button_icon.setMaximumSize(QSize(width, height))
        self.setStyleSheet('LineEditSearch '
                           '{{padding-right: {0}px;}}'.format(width))

    def set_icon_visibility(self, value):
        """Set clear button visibility."""
        self._show_icons = value
        self.update_box()

    def setProperty(self, name, value):
        """Override Qt method."""
        super(LineEditSearch, self).setProperty(name, value)
        self.style().unpolish(self)
        self.style().polish(self)
        self.update()

    def update_box(self, text=None):
        """Update icon visibility and status."""
        if text:
            if self._show_icons:
                self.button_icon.setIcon(QIcon())
            self.button_icon.setProperty('_remove', True)
        else:
            if self._show_icons:
                self.button_icon.setIcon(QIcon())
            self.button_icon.setProperty('_remove', False)
        self._empty = not bool(text)
        self.button_icon.setDisabled(self._empty)

    def clear_text(self):
        """Clear all text in the line edit."""
        self.setText('')
        self.setFocus()
        self.update_box()

    def update_style_sheet(self, style_sheet=None):
        """Update custom CSS style sheet."""
        if style_sheet is not None:
            self.button_icon.setStyleSheet(style_sheet)

    def keyPressEvent(self, event):
        """Override Qt method."""
        key = event.key()
        if key in [Qt.Key_Escape]:
            self.clear_text()
        else:
            super(LineEditSearch, self).keyPressEvent(event)


# --- Local testing
# -----------------------------------------------------------------------------
def test():  # pragma : no cover
    """Run loca tests."""
    from anaconda_navigator.utils.qthelpers import qapplication
    from anaconda_navigator.config import get_home_dir
    app = qapplication()

    widget_editable = EditableLineEdit('Project name', 'my-project',
                                       regex='[A-Za-z0-9_\- ]{1,20}')
    widget_editable.show()

    widget_path = EditablePathEdit('Icon', '',
                                   basedir=get_home_dir(),
                                   fileselect=True,
                                   caption='Select icon file',
                                   filters="Image files (*.png *.jpg)")
    widget_path.show()

    widget_checkbox = MessageCheckBox.warning(
        None,
        'Delete project',
        'Do you really want to delete project {0}?'.format(''),
        checkbox_text='Delete project files',
        buttons=MessageCheckBox.Yes | MessageCheckBox.No, )
    widget_checkbox.show()
    app.exec_()


if __name__ == '__main__':  # pragma : no cover
    test()
