# Created By: Virgil Dupras
# Created On: 2011-09-06
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html

from PyQt5.QtCore import Qt, QAbstractListModel, QItemSelection, QItemSelectionModel


class SelectableList(QAbstractListModel):
    def __init__(self, model, view, **kwargs):
        super().__init__(**kwargs)
        self._updating = False
        self.view = view
        self.model = model
        self.view.setModel(self)
        self.model.view = self

    # --- Override
    def data(self, index, role):
        if not index.isValid():
            return None
        # We need EditRole for QComboBoxes with setEditable(True)
        if role in {Qt.DisplayRole, Qt.EditRole}:
            return self.model[index.row()]
        return None

    def rowCount(self, index):
        if index.isValid():
            return 0
        return len(self.model)

    # --- Virtual
    def _updateSelection(self):
        raise NotImplementedError()

    def _restoreSelection(self):
        raise NotImplementedError()

    # --- model --> view
    def refresh(self):
        self._updating = True
        self.beginResetModel()
        self.endResetModel()
        self._updating = False
        self._restoreSelection()

    def update_selection(self):
        self._restoreSelection()


class ComboboxModel(SelectableList):
    def __init__(self, model, view, **kwargs):
        super().__init__(model, view, **kwargs)
        self.view.currentIndexChanged[int].connect(self.selectionChanged)

    # --- Override
    def _updateSelection(self):
        index = self.view.currentIndex()
        if index != self.model.selected_index:
            self.model.select(index)

    def _restoreSelection(self):
        index = self.model.selected_index
        if index is not None:
            self.view.setCurrentIndex(index)

    # --- Events
    def selectionChanged(self, index):
        if not self._updating:
            self._updateSelection()


class ListviewModel(SelectableList):
    def __init__(self, model, view, **kwargs):
        super().__init__(model, view, **kwargs)
        self.view.selectionModel().selectionChanged[
            (QItemSelection, QItemSelection)
        ].connect(self.selectionChanged)

    # --- Override
    def _updateSelection(self):
        newIndexes = [
            modelIndex.row() for modelIndex in self.view.selectionModel().selectedRows()
        ]
        if newIndexes != self.model.selected_indexes:
            self.model.select(newIndexes)

    def _restoreSelection(self):
        newSelection = QItemSelection()
        for index in self.model.selected_indexes:
            newSelection.select(self.createIndex(index, 0), self.createIndex(index, 0))
        self.view.selectionModel().select(
            newSelection, QItemSelectionModel.ClearAndSelect
        )
        if len(newSelection.indexes()):
            currentIndex = newSelection.indexes()[0]
            self.view.selectionModel().setCurrentIndex(
                currentIndex, QItemSelectionModel.Current
            )
            self.view.scrollTo(currentIndex)

    # --- Events
    def selectionChanged(self, index):
        if not self._updating:
            self._updateSelection()
