#! /usr/bin/env python
# -*- coding: utf-8 -*-

"""
Module that contains base classes for list views
"""

from __future__ import print_function, division, absolute_import

import os
import glob

from Qt.QtCore import *
from Qt.QtWidgets import *
from Qt.QtGui import *

from tpDcc.libs.python import python
from tpDcc.libs.qt.widgets import models


class BaseListView(QListView, object):
    """
    Base class for list views
    """

    def __ini__(self, parent=None):
        super(BaseListView, self).__init__(parent=parent)


class ListView(BaseListView, object):
    """
    Extends basic QListView functionality
    """

    current_selection_changed = Signal(object, object)
    middle_clicked = Signal(QModelIndex)

    def __init__(self, parent=None):
        super(ListView, self).__init__(parent)

    # region Public Functions
    def appendItem(self, item):
        """
        Adds a new item to the list view model
        :param item: variant
        """

        if self.model():
            self.model().appendItem(item)
    # endregion

    # region Override Functions
    def selectionChanged(self, selected, deselected):
        """
        Override selectionChanged behavior
        :param selected: list<variant>, new selection
        :param deselected: list<variant>, previous selection
        :warning: This method is override to avoid a Qt 4.7.0 QModelIndexList destructor crash.
            See ItemSelection for more information.
        """

        self.current_selection_changed.emit(models.ItemSelection(selected), models.ItemSelection(deselected))
        super(ListView, self).selectionChanged(models.ItemSelection(selected), models.ItemSelection(deselected))

    def selectedIndexes(self):
        """
        Override selectedIndexes behavior
        :warning: This method is override to avoid  a Qt 4.7.0 QModelIndexList destructor crash.
            See ItemSelection for more information.
        """

        item_selection = models.ItemSelection(self.selectionModel().selection())
        return item_selection.indexes()

    def mousePressEvent(self, event):
        """
        Override mousePressEvent behavior to add a custom middle click signal
        :param event: QMouseEvent
        """

        if event.button() == Qt.MidButton:
            model_index = self.indexAt(event.pos())
            if model_index.row() >= 0:
                self.middle_clicked.emit(model_index)
        super(ListView, self).mousePressEvent(event)
    # endregion


class DraggableListView(ListView, object):
    """
    Extends ListView functionality width draggable functionality
    """

    addedItemDir = Signal(list)

    def __init__(self, parent=None):
        super(DraggableListView, self).__init__(parent=parent)

        self._accepted_files = list()

        self.setEditTriggers(QListView.NoEditTriggers)
        self.setDragEnabled(True)
        self.setDragDropMode(QListView.DragOnly)
        self.setDefaultDropAction(Qt.IgnoreAction)
        self.setAcceptDrops(True)
        self.setIconSize(QSize(120, 120))
        self.setViewMode(QListView.IconMode)
        self.setMovement(QListView.Snap)
        self.setResizeMode(QListView.Adjust)
        self.setUniformItemSizes(True)
        self.setMouseTracking(True)

    def startDrag(self, supported_actions):
        """
        Function that is called when we start dragging an item
        This function set ups the mime data and creates a copy of the image
        of the item that is show in cursor position while dragging action
        is enabled
        """

        index = self.currentIndex()
        model = self.model()
        item = model.itemFromIndex(index)
        drag = QDrag(self)
        mime_data = QMimeData()
        mime_data.setData('item_text', QByteArray(str(item.text())))
        mime_data.setData('item_size', QByteArray('%.1f %.1f' % (item.size.width(), item.size.height())))
        url = QUrl.fromLocalFile(item.text())
        mime_data.setUrls(url)
        drag.setMimeData(mime_data)
        pixmap = item.icon().pixmap(50, 50)
        drag.setDragCursor(pixmap, Qt.CopyAction)
        drag.start()

    def dragEnterEvent(self, event):
        mime_data = event.mimeData()
        if mime_data.hasUrls():
            for path in map(lambda x: x.toLocalFile(), mime_data.urls()):
                if os.path.isdir(path) or os.path.isfile(path) and \
                        os.path.splitext(path)[-1].lower() in self._accepted_files:
                    self.setDragDropMode(QListView.InternalMove)
                    event.accept()
                    break
        super(DraggableListView, self).dragEnterEvent(event)

    def dragMoveEvent(self, event):
        event.accept()
        super(DraggableListView, self).dragMoveEvent(event)

    def dropEvent(self, event):
        mime_data = event.mimeData()
        if mime_data.hasUrls():
            send_data = list()
            for path in map(lambda x: x.toLocalFile(), mime_data.urls()):
                for file in self._accepted_files:
                    if os.path.isdir(path) and glob.glob(os.path.join(path, '*' + file))\
                            or os.path.isfile(path) and os.path.splitext(path)[-1].lower() == file:
                        send_data.append(path)
            if send_data:
                self.addedItemDir.emit(send_data)
            self.setDragEnabled(True)
            self.setDragDropMode(QListView.DragOnly)
            self.setDefaultDropAction(Qt.IgnoreAction)
            self.setAcceptDrops(True)
            super(DraggableListView, self).dropEvent(event)

    def set_accepted_files(self, list_files):

        list_files = python.force_list(list_files)

        for f in list_files:
            if not f.startswith('.'):
                f = '.' + f
            self._accepted_files.append(f)


class BaseTableView(QTableView, object):
    def __init__(self, parent=None, **kwargs):
        super(BaseTableView, self).__init__(parent=parent, **kwargs)

        self._last_indexes = list()

        self.installEventFilter(self)

    def focusOutEvent(self, event):
        if self.selectionModel().selectedIndexes():
            for index in self.selectionModel().selectedRows():
                self._last_indexes.append(QPersistentModelIndex(index))
        if self._last_indexes:
            for i in self._last_indexes:
                self.selectionModel().setCurrentIndex(i, QItemSelectionModel.Select)
        event.accept()

    def get_selected_indexes(self):
        """
        Returns the selected indexes
        """

        return self.selectionModel().selectedIndexes()

    def get_selected_rows(self):
        """
        Returns the selected rows
        """

        return self.selectionModel().selectedRows()


class BaseTreeView(QTreeView, object):
    """
    Base class for tree views
    """

    def __init__(self, parent=None):
        super(BaseTreeView, self).__init__(parent=parent)

    def expand_tree(self, root_node):
        """
        Expands all the collapsed elements in a tree starting at the rootNode
        :param root_node: Start node from which we start expanding the tree
        """

        parent = root_node.parent()
        parent_id = self.model().createIndex(parent.row(), 0, parent) if parent else QModelIndex()
        index = self.model().index(root_node.row(), 0, parent_id)
        self.setExpanded(index, True)
        for child in root_node.children:
            self.expand_tree(child)
