# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)

"""Layout dialogs"""

# Standard library imports
import sys

# Third party imports
from qtpy.QtCore import QAbstractTableModel, QModelIndex, QSize, Qt
from qtpy.compat import from_qvariant, to_qvariant
from qtpy.QtWidgets import (QAbstractItemView, QDialog,
                            QDialogButtonBox, QGroupBox, QHBoxLayout,
                            QPushButton, QTableView, QVBoxLayout)

# Local imports
from spyder.api.widgets.comboboxes import SpyderComboBox
from spyder.api.widgets.dialogs import SpyderDialogButtonBox
from spyder.config.base import _
from spyder.py3compat import to_text_string


class LayoutModel(QAbstractTableModel):
    """ """
    def __init__(self, parent, names, ui_names, order, active, read_only):
        super(LayoutModel, self).__init__(parent)

        # variables
        self._parent = parent
        self.names = names
        self.ui_names = ui_names
        self.order = order
        self.active = active
        self.read_only = read_only
        self._rows = []
        self.set_data(names, ui_names, order, active, read_only)

    def set_data(self, names, ui_names, order, active, read_only):
        """ """
        self._rows = []
        self.names = names
        self.ui_names = ui_names
        self.order = order
        self.active = active
        self.read_only = read_only
        for name in order:
            index = names.index(name)
            if name in active:
                row = [ui_names[index], name, True]
            else:
                row = [ui_names[index], name, False]
            self._rows.append(row)

    def flags(self, index):
        """Override Qt method"""
        row = index.row()
        ui_name, name, state = self.row(row)

        if name in self.read_only:
            return Qt.ItemFlag(0)
        if not index.isValid():
            return Qt.ItemFlag.ItemIsEnabled
        column = index.column()
        if column in [0]:
            return (Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable |
                    Qt.ItemFlag.ItemIsUserCheckable |
                    Qt.ItemFlag.ItemIsEditable)
        else:
            return Qt.ItemFlag.ItemIsEnabled

    def data(self, index, role=Qt.DisplayRole):
        """Override Qt method"""
        if not index.isValid() or not 0 <= index.row() < len(self._rows):
            return to_qvariant()
        row = index.row()
        column = index.column()

        ui_name, name, state = self.row(row)

        if role == Qt.DisplayRole or role == Qt.EditRole:
            if column == 0:
                return to_qvariant(ui_name)
        elif role == Qt.UserRole:
            if column == 0:
                return to_qvariant(name)
        elif role == Qt.CheckStateRole:
            if column == 0:
                if state:
                    return Qt.Checked
                else:
                    return Qt.Unchecked
            if column == 1:
                return to_qvariant(state)
        return to_qvariant()

    def setData(self, index, value, role):
        """Override Qt method"""
        row = index.row()
        ui_name, name, state = self.row(row)

        if role == Qt.CheckStateRole:
            self.set_row(row, [ui_name, name, not state])
            self._parent.setCurrentIndex(index)
            self._parent.setFocus()
            self.dataChanged.emit(index, index)
            return True
        elif role == Qt.EditRole:
            self.set_row(
                row, [from_qvariant(value, to_text_string), name, state])
            self.dataChanged.emit(index, index)
            return True
        return True

    def rowCount(self, index=QModelIndex()):
        """Override Qt method"""
        return len(self._rows)

    def columnCount(self, index=QModelIndex()):
        """Override Qt method"""
        return 2

    def row(self, rownum):
        """ """
        if self._rows == [] or rownum >= len(self._rows):
            return [None, None, None]
        else:
            return self._rows[rownum]

    def set_row(self, rownum, value):
        """ """
        self._rows[rownum] = value


class LayoutSaveDialog(QDialog):
    """ """
    def __init__(self, parent, order):
        super(LayoutSaveDialog, self).__init__(parent)

        # variables
        self._parent = parent

        # widgets
        self.combo_box = SpyderComboBox(self)
        self.combo_box.addItems(order)
        self.combo_box.setEditable(True)
        self.combo_box.clearEditText()
        self.button_box = SpyderDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self
        )
        self.button_ok = self.button_box.button(QDialogButtonBox.Ok)
        self.button_cancel = self.button_box.button(QDialogButtonBox.Cancel)

        # widget setup
        self.button_ok.setEnabled(False)
        self.dialog_size = QSize(300, 100)
        self.setWindowTitle('Save layout as')
        self.setModal(True)
        self.setMinimumSize(self.dialog_size)
        self.setFixedSize(self.dialog_size)

        # layouts
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.combo_box)
        self.layout.addWidget(self.button_box)
        self.setLayout(self.layout)

        # signals and slots
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.close)
        self.combo_box.editTextChanged.connect(self.check_text)

    def check_text(self, text):
        """Disable empty layout name possibility"""
        if to_text_string(text) == u'':
            self.button_ok.setEnabled(False)
        else:
            self.button_ok.setEnabled(True)


class LayoutSettingsDialog(QDialog):
    """Layout settings dialog"""
    def __init__(self, parent, names, ui_names, order, active, read_only):
        super(LayoutSettingsDialog, self).__init__(parent)
        # variables
        self._parent = parent
        self._selection_model = None
        self.names = names
        self.ui_names = ui_names
        self.order = order
        self.active = active
        self.read_only = read_only

        # widgets
        self.button_move_up = QPushButton(_('Move up'))
        self.button_move_down = QPushButton(_('Move down'))
        self.button_delete = QPushButton(_('Delete layout'))
        self.button_box = SpyderDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self
        )
        self.group_box = QGroupBox(_("Layout display and order"))
        self.table = QTableView(self)
        self.ok_button = self.button_box.button(QDialogButtonBox.Ok)
        self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel)
        self.cancel_button.setDefault(True)
        self.cancel_button.setAutoDefault(True)

        # widget setup
        self.dialog_size = QSize(300, 200)
        self.setMinimumSize(self.dialog_size)
        self.setFixedSize(self.dialog_size)
        self.setWindowTitle('Layout Settings')

        self.table.setModel(
            LayoutModel(self.table, names, ui_names, order, active, read_only))
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.verticalHeader().hide()
        self.table.horizontalHeader().hide()
        self.table.setAlternatingRowColors(True)
        self.table.setShowGrid(False)
        self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setColumnHidden(1, True)

        # need to keep a reference for pyside not to segfault!
        self._selection_model = self.table.selectionModel()

        # layout
        buttons_layout = QVBoxLayout()
        buttons_layout.addWidget(self.button_move_up)
        buttons_layout.addWidget(self.button_move_down)
        buttons_layout.addStretch()
        buttons_layout.addWidget(self.button_delete)

        group_layout = QHBoxLayout()
        group_layout.addWidget(self.table)
        group_layout.addLayout(buttons_layout)
        self.group_box.setLayout(group_layout)

        layout = QVBoxLayout()
        layout.addWidget(self.group_box)
        layout.addWidget(self.button_box)

        self.setLayout(layout)

        # signals and slots
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.close)
        self.button_delete.clicked.connect(self.delete_layout)
        self.button_move_up.clicked.connect(lambda: self.move_layout(True))
        self.button_move_down.clicked.connect(lambda: self.move_layout(False))
        self.table.model().dataChanged.connect(
           lambda: self.selection_changed(None, None))
        self._selection_model.selectionChanged.connect(
           lambda: self.selection_changed(None, None))

        # focus table
        if len(names) > len(read_only):
            row = len(read_only)
            index = self.table.model().index(row, 0)
            self.table.setCurrentIndex(index)
            self.table.setFocus()
        else:
            # initial button state in case only programmatic layouts
            # are available
            self.button_move_up.setDisabled(True)
            self.button_move_down.setDisabled(True)
            self.button_delete.setDisabled(True)

    def delete_layout(self):
        """Delete layout from the config."""
        names, ui_names, order, active, read_only = (
            self.names, self.ui_names, self.order, self.active, self.read_only)
        row = self.table.selectionModel().currentIndex().row()
        ui_name, name, state = self.table.model().row(row)

        if name not in read_only:
            name = from_qvariant(
                self.table.selectionModel().currentIndex().data(),
                to_text_string)
            if ui_name in ui_names:
                index = ui_names.index(ui_name)
            else:
                # In case nothing has focus in the table
                return
            if index != -1:
                order.remove(ui_name)
                names.remove(ui_name)
                ui_names.remove(ui_name)
                if name in active:
                    active.remove(ui_name)
                self.names, self.ui_names, self.order, self.active = (
                    names, ui_names, order, active)
                self.table.model().set_data(
                    names, ui_names, order, active, read_only)
                index = self.table.model().index(0, 0)
                self.table.setCurrentIndex(index)
                self.table.setFocus()
                self.selection_changed(None, None)
                if len(order) == 0 or len(names) == len(read_only):
                    self.button_move_up.setDisabled(True)
                    self.button_move_down.setDisabled(True)
                    self.button_delete.setDisabled(True)

    def move_layout(self, up=True):
        """ """
        names, ui_names, order, active, read_only = (
            self.names, self.ui_names, self.order, self.active, self.read_only)
        row = self.table.selectionModel().currentIndex().row()
        row_new = row
        _ui_name, name, _state = self.table.model().row(row)

        if name not in read_only:
            if up:
                row_new -= 1
            else:
                row_new += 1

            if order[row_new] not in read_only:
                order[row], order[row_new] = order[row_new], order[row]

                self.order = order
                self.table.model().set_data(
                    names, ui_names, order, active, read_only)
                index = self.table.model().index(row_new, 0)
                self.table.setCurrentIndex(index)
                self.table.setFocus()
                self.selection_changed(None, None)

    def selection_changed(self, selection, deselection):
        """ """
        model = self.table.model()
        index = self.table.currentIndex()
        row = index.row()
        order, names, ui_names, active, read_only = (
            self.order, self.names, self.ui_names, self.active, self.read_only)

        state = model.row(row)[2]
        ui_name = model.row(row)[0]

        # Check if name changed
        if ui_name not in ui_names:  # Did changed
            # row == -1, means no items left to delete
            if row != -1 and len(names) > len(read_only):
                old_name = order[row]
                order[row] = ui_name
                names[names.index(old_name)] = ui_name
                ui_names = names
                if old_name in active:
                    active[active.index(old_name)] = ui_name

        # Check if checkbox clicked
        if state:
            if ui_name not in active:
                active.append(ui_name)
        else:
            if ui_name in active:
                active.remove(ui_name)

        self.active = active
        self.order = order
        self.names = names
        self.ui_names = ui_names
        self.button_move_up.setDisabled(False)
        self.button_move_down.setDisabled(False)

        if row == 0:
            self.button_move_up.setDisabled(True)
        if row == len(names) - 1:
            self.button_move_down.setDisabled(True)
        if len(names) == 0:
            self.button_move_up.setDisabled(True)
            self.button_move_down.setDisabled(True)


def test():
    """Run layout test widget test"""
    from spyder.utils.qthelpers import qapplication

    app = qapplication()
    names = ['test', 'tester', '20', '30', '40']
    ui_names = ['L1', 'L2', '20', '30', '40']
    order = ['test', 'tester', '20', '30', '40']
    read_only = ['test', 'tester']
    active = ['test', 'tester']
    widget_1 = LayoutSettingsDialog(
        None, names, ui_names, order, active, read_only)
    widget_2 = LayoutSaveDialog(None, order)
    widget_1.show()
    widget_2.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    test()
