from pyqt_compat.QtCore import Qt
from pyqt_compat.QtCore import QSettings, pyqtSlot, QAbstractTableModel, QModelIndex, QPoint, QSize
from . import plugin_base, tuflow_plugin_item
from pyqt_compat.QtWidgets import QFormLayout, QLineEdit, QStyle, QFileDialog, QSpinBox, QTableWidget
from pyqt_compat.QtWidgets import QHeaderView, QCheckBox, QTableView, QHeaderView, QStyledItemDelegate

from pyqt_compat import (QT_CHECKED, QT_HORIZONTAL, QT_ITEM_DATA_CHECK_STATE_ROLE, QT_ITEM_DATA_DISPLAY_ROLE,
                         QT_ITEM_DATA_EDIT_ROLE, QT_ITEM_FLAG_ITEM_IS_EDITABLE, QT_ITEM_FLAG_ITEM_IS_ENABLED,
                         QT_ITEM_FLAG_ITEM_IS_SELECTABLE, QT_ITEM_FLAG_ITEM_IS_USER_CHECKABLE, QT_UNCHECKED)
from pyqt_compat.QtGui import QPixmap

import bit_functions

class SpinBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent

    def createEditor(self, parent, option, index):
        editor = QSpinBox(parent)
        editor.setMinimum(0)
        editor.setMaximum(100)
        return editor

    def setEditorData(self, editor, index):
        value = index.data(QT_ITEM_DATA_EDIT_ROLE)
        editor.setValue(value if value else 0)

    def setModelData(self, editor, model, index):
        editor.interpretText()
        value = editor.value()
        model.setData(index, value, QT_ITEM_DATA_EDIT_ROLE)

    def sizeHint(self, option, index):
        return QSize(100, 30)

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

class ConfigurationTableModel(QAbstractTableModel):
    def __init__(self, configs):
        super().__init__()
        self.configs = configs
        self.max_num_gpus = 24

    def rowCount(self, parent=QModelIndex()):
        return len(self.configs)

    def columnCount(self, parent=QModelIndex()):
        return self.max_num_gpus + 1

    def headerData(self, section, orientation, role):
        if role != QT_ITEM_DATA_DISPLAY_ROLE:
            return None

        if orientation == QT_HORIZONTAL:
            if section < self.max_num_gpus:
                return f"GPU {section + 1}"
            elif section == self.max_num_gpus:
                return "Number CPU threads"
            else:
                return "ERR"
        else:
            return str(section + 1)

    def data(self, index, role=QT_ITEM_DATA_DISPLAY_ROLE):
        if index.column() < self.max_num_gpus:
            if role == QT_ITEM_DATA_CHECK_STATE_ROLE:
                if bit_functions.test_bit(self.configs[index.row()][0], index.column()):
                    #print("returning checked")
                    return QT_CHECKED
                else:
                    #print("returning unchecked")
                    return QT_UNCHECKED
        elif index.column() == self.max_num_gpus:
            if role == QT_ITEM_DATA_DISPLAY_ROLE or role == QT_ITEM_DATA_EDIT_ROLE:
                return self.configs[index.row()][1]
        else:
            return None
        return None

    def setData(self, index, value, role=QT_ITEM_DATA_EDIT_ROLE):
        config_row = self.configs[index.row()]
        if index.column() < self.max_num_gpus:
            if role == QT_ITEM_DATA_CHECK_STATE_ROLE:
                first_value = config_row[0]
                first_value = bit_functions.toggle_bit(first_value, index.column())
                self.configs[index.row()] = (first_value, config_row[1])
                return True
        else:
            if role == QT_ITEM_DATA_EDIT_ROLE:
                self.configs[index.row()] = (config_row[0], value)
                return True
        return False

    def flags(self, index):
        if index.column() < self.max_num_gpus:
            return (QT_ITEM_FLAG_ITEM_IS_USER_CHECKABLE | QT_ITEM_FLAG_ITEM_IS_EDITABLE |
                    QT_ITEM_FLAG_ITEM_IS_ENABLED | QT_ITEM_FLAG_ITEM_IS_SELECTABLE)
        else:
            return QT_ITEM_FLAG_ITEM_IS_ENABLED | QT_ITEM_FLAG_ITEM_IS_EDITABLE | QT_ITEM_FLAG_ITEM_IS_SELECTABLE

    def set_number_configurations(self, num_new_configs):
        if len(self.configs) == num_new_configs:
            return
        self.beginResetModel()
        if len(self.configs) < num_new_configs:
            while len(self.configs) < num_new_configs:
                self.configs.append((0, 4))
        else:
            self.configs = self.configs[:num_new_configs]
        self.endResetModel()
