from IPython.terminal.embed import embed
from nixview.util.file_handler import FileHandler
from PyQt5.QtCore import QAbstractTableModel, Qt
import numpy as np

from nixview.util.enums import NodeType

from IPython import embed

class TableModel (QAbstractTableModel):

    def __init__(self, file_handler, data_view, page=0, parent=None) -> None:
        super(TableModel, self).__init__(parent)
        self._file_handler = file_handler
        self._data_view = data_view
        self._page = page
        self._dim_count = data_view.dimension_count
        self._item = self._data_view.item
        self._dimension_descriptors = self._file_handler.request_dimensions(self._data_view.item.block_id, self._data_view.item.id)
        self._dimension_tooltips = [self.dimension_tool_tip(i) for i in range(self._dim_count)]
        self._data_tooltip = self.create_data_tooltip()
        self._cols = self._data_view.full_shape[1] if len(self._data_view.full_shape) > 1 else 1
        self._rows = self._data_view.full_shape[0]
        self.insertColumns(0, self._cols)
        self.insertRows(0, self._rows)
        self._slice = [0 for i in range(len(self._data_view.full_shape))]
        if len(self._data_view.full_shape) > 2:
            self._slice[-1] = self._page
        self.createHeader()

    def create_data_tooltip(self):
        label = self._item.label if self._item.label is not None else ""
        unit = "[%s]" % self._item.unit if self._item.unit is not None else ""
        return "%s %s" % (label, unit)

    def rowCount(self, parent):
        return self._rows

    def columnCount(self, parent):
        return self._cols

    def dimension_tool_tip(self, index):
        label = self._dimension_descriptors[index].label if self._dimension_descriptors[index].label is not None else ""
        unit = "[%s]" % self._dimension_descriptors[index].unit if self._dimension_descriptors[index].unit is not None else ""
        return "%s %s" % (label, unit)

    def convert_axis_to_string(self, axis):
        is_numeric = False
        try:
            float(axis[0])
            is_numeric = True
        except:
            pass
        if is_numeric:
            axis = np.round(np.asarray(axis, dtype=float), 5)
            return list(map(str, axis))
        else:
            return axis

    def createHeaderDataArray(self):
        if self._dim_count == 1:
            temp = self._file_handler.request_axis(self._data_view.item.block_id,
                                                   self._data_view.item.id, 0,
                                                   self.rowCount(None))
            self._vheader = self.convert_axis_to_string(temp)
            self._hheader = ["1"]
        elif self._dim_count > 1:
            temp = self._file_handler.request_axis(self._data_view.item.block_id,
                                                   self._data_view.item.id, 0, 
                                                   self.rowCount(None))
            self._vheader = self.convert_axis_to_string(temp)
            temp = self._file_handler.request_axis(self._data_view.item.block_id, 
                                                   self._data_view.item.id, 1, 
                                                   self.columnCount(None))
            self._hheader = self.convert_axis_to_string(temp)

    def createHeader(self):
        if self._data_view.item.entity_type == NodeType.DataArray:
            self.createHeaderDataArray()
        else:
            self._vheader = np.arange(self.rowCount(None))
            self._hheader = np.arange(self.columnCount(None))

        """
        if (array.getDimension(1).dimensionType() == nix::DimensionType::Set) {
            v_labels = array.getDimension(1).asSetDimension().labels();
        }
        if (shape.size() > 1) {
            if (array.getDimension(2).dimensionType() == nix::DimensionType::Set) {
                h_labels = array.getDimension(2).asSetDimension().labels();
            }
        }
        """

    def data(self, index, role):
        if not index.isValid() or (role != Qt.DisplayRole and role != Qt.ToolTipRole):
            return None
        if role == Qt.ToolTipRole:
            return self._data_tooltip
        d = ""
        if (index.row() < self._rows) and (index.column() < self._cols):
            self._slice[0] = index.row()
            if len(self._slice) == 2:
                self._slice[1] = index.column()
            d = self._data_view._buffer[tuple(self._slice)]

        return str(np.round(d, 5))

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole and role != Qt.ToolTipRole:
            return super().headerData(section, orientation, role)

        if role == Qt.DisplayRole:
            if orientation == Qt.Vertical:
                return self._vheader[section]
            else:
                return self._hheader[section]

        if role == Qt.ToolTipRole:
            if orientation == Qt.Vertical:
                return self._dimension_tooltips[0]
            else:
                return self._dimension_tooltips[1] if self._dim_count > 1 else self._data_tooltip