# Created By: Virgil Dupras
# Created On: 2009-04-25
# 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

import urllib.parse

from PyQt5.QtCore import pyqtSignal, Qt, QRect, QUrl, QModelIndex, QItemSelection
from PyQt5.QtWidgets import (
    QComboBox,
    QStyledItemDelegate,
    QStyle,
    QStyleOptionComboBox,
    QStyleOptionViewItem,
    QApplication,
)
from PyQt5.QtGui import QBrush

from hscommon.trans import trget
from qtlib.tree_model import RefNode, TreeModel

tr = trget("ui")

HEADERS = [tr("Name"), tr("State")]
STATES = [tr("Normal"), tr("Reference"), tr("Excluded")]


class DirectoriesDelegate(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = QComboBox(parent)
        editor.addItems(STATES)
        return editor

    def paint(self, painter, option, index):
        self.initStyleOption(option, index)
        # No idea why, but this cast is required if we want to have access to the V4 valuess
        option = QStyleOptionViewItem(option)
        if (index.column() == 1) and (option.state & QStyle.State_Selected):
            cboption = QStyleOptionComboBox()
            cboption.rect = option.rect
            # On OS X (with Qt4.6.0), adding State_Enabled to the flags causes the whole drawing to
            # fail (draw nothing), but it's an OS X only glitch. On Windows, it works alright.
            cboption.state |= QStyle.State_Enabled
            QApplication.style().drawComplexControl(
                QStyle.CC_ComboBox, cboption, painter
            )
            painter.setBrush(option.palette.text())
            rect = QRect(option.rect)
            rect.setLeft(rect.left() + 4)
            painter.drawText(rect, Qt.AlignLeft, option.text)
        else:
            super().paint(painter, option, index)

    def setEditorData(self, editor, index):
        value = index.model().data(index, Qt.EditRole)
        editor.setCurrentIndex(value)
        editor.showPopup()

    def setModelData(self, editor, model, index):
        value = editor.currentIndex()
        model.setData(index, value, Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


class DirectoriesModel(TreeModel):
    def __init__(self, model, view, **kwargs):
        super().__init__(**kwargs)
        self.model = model
        self.model.view = self
        self.view = view
        self.view.setModel(self)

        self.view.selectionModel().selectionChanged[
            (QItemSelection, QItemSelection)
        ].connect(self.selectionChanged)

    def _createNode(self, ref, row):
        return RefNode(self, None, ref, row)

    def _getChildren(self):
        return list(self.model)

    def columnCount(self, parent=QModelIndex()):
        return 2

    def data(self, index, role):
        if not index.isValid():
            return None
        node = index.internalPointer()
        ref = node.ref
        if role == Qt.DisplayRole:
            if index.column() == 0:
                return ref.name
            else:
                return STATES[ref.state]
        elif role == Qt.EditRole and index.column() == 1:
            return ref.state
        elif role == Qt.ForegroundRole:
            state = ref.state
            if state == 1:
                return QBrush(Qt.blue)
            elif state == 2:
                return QBrush(Qt.red)
        return None

    def dropMimeData(self, mimeData, action, row, column, parentIndex):
        # the data in mimeData is urlencoded **in utf-8**!!! What we do is to decode, the mime data
        # with 'ascii', which works since it's urlencoded. Then, we pass that to urllib.
        if not mimeData.hasFormat("text/uri-list"):
            return False
        data = bytes(mimeData.data("text/uri-list")).decode("ascii")
        unquoted = urllib.parse.unquote(data)
        urls = unquoted.split("\r\n")
        paths = [QUrl(url).toLocalFile() for url in urls if url]
        for path in paths:
            self.model.add_directory(path)
        self.foldersAdded.emit(paths)
        self.reset()
        return True

    def flags(self, index):
        if not index.isValid():
            return Qt.ItemIsEnabled | Qt.ItemIsDropEnabled
        result = Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDropEnabled
        if index.column() == 1:
            result |= Qt.ItemIsEditable
        return result

    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal:
            if role == Qt.DisplayRole and section < len(HEADERS):
                return HEADERS[section]
        return None

    def mimeTypes(self):
        return ["text/uri-list"]

    def setData(self, index, value, role):
        if not index.isValid() or role != Qt.EditRole or index.column() != 1:
            return False
        node = index.internalPointer()
        ref = node.ref
        ref.state = value
        return True

    def supportedDropActions(self):
        # Normally, the correct action should be ActionLink, but the drop doesn't work. It doesn't
        # work with ActionMove either. So screw that, and accept anything.
        return Qt.ActionMask

    # --- Events
    def selectionChanged(self, selected, deselected):
        newNodes = [
            modelIndex.internalPointer().ref
            for modelIndex in self.view.selectionModel().selectedRows()
        ]
        self.model.selected_nodes = newNodes

    # --- Signals
    foldersAdded = pyqtSignal(list)

    # --- model --> view
    def refresh(self):
        self.reset()

    def refresh_states(self):
        self.refreshData()
