from meshroom.common.qt import QObjectListModel

from PySide2.QtCore import QObject, Slot, Signal, Property
from PySide2.QtCharts import QtCharts

import csv
import os
import logging


class CsvData(QObject):
    """Store data from a CSV file."""
    def __init__(self, parent=None):
        """Initialize the object without any parameter."""
        super(CsvData, self).__init__(parent=parent)
        self._filepath = ""
        self._data = QObjectListModel(parent=self)  # List of CsvColumn
        self._ready = False
        self.filepathChanged.connect(self.updateData)

    @Slot(int, result=QObject)
    def getColumn(self, index):
        return self._data.at(index)

    @Slot(result=str)
    def getFilepath(self):
        return self._filepath

    @Slot(result=int)
    def getNbColumns(self):
        if self._ready:
            return len(self._data)
        else:
            return 0

    @Slot(str)
    def setFilepath(self, filepath):
        if self._filepath == filepath:
            return
        self.setReady(False)
        self._filepath = filepath
        self.filepathChanged.emit()

    def setReady(self, ready):
        if self._ready == ready:
            return
        self._ready = ready
        self.readyChanged.emit()

    @Slot()
    def updateData(self):
        self.setReady(False)
        self._data.clear()
        newColumns = self.read()
        if newColumns:
            self._data.setObjectList(newColumns)
            self.setReady(True)

    def read(self):
        """Read the CSV file and return a list containing CsvColumn objects."""
        if not self._filepath or not self._filepath.lower().endswith(".csv") or not os.path.isfile(self._filepath):
            return []

        dataList = []
        try:
            csvRows = []
            with open(self._filepath, "r") as fp:
                reader = csv.reader(fp)
                for row in reader:
                    csvRows.append(row)
            # Create the objects in dataList
            # with the first line elements as objects' title
            for elt in csvRows[0]:
                dataList.append(CsvColumn(elt)) # , parent=self._data
            # Populate the content attribute
            for elt in csvRows[1:]:
                for idx, value in enumerate(elt):
                    dataList[idx].appendValue(value)
        except Exception as e:
            logging.error("CsvData: Failed to load file: {}\n{}".format(self._filepath, str(e)))

        return dataList

    filepathChanged = Signal()
    filepath = Property(str, getFilepath, setFilepath, notify=filepathChanged)
    readyChanged = Signal()
    ready = Property(bool, lambda self: self._ready, notify=readyChanged)
    data = Property(QObject, lambda self: self._data, notify=readyChanged)
    nbColumns = Property(int, getNbColumns, notify=readyChanged)


class CsvColumn(QObject):
    """Store content of a CSV column."""
    def __init__(self, title="", parent=None):
        """Initialize the object with optional column title parameter."""
        super(CsvColumn, self).__init__(parent=parent)
        self._title = title
        self._content = []

    def appendValue(self, value):
        self._content.append(value)

    @Slot(result=str)
    def getFirst(self):
        if not self._content:
            return ""
        return self._content[0]

    @Slot(result=str)
    def getLast(self):
        if not self._content:
            return ""
        return self._content[-1]

    @Slot(QtCharts.QXYSeries)
    def fillChartSerie(self, serie):
        """Fill XYSerie used for displaying QML Chart."""
        if not serie:
            return
        serie.clear()
        for index, value in enumerate(self._content):
            serie.append(float(index), float(value))

    title = Property(str, lambda self: self._title, constant=True)
    content = Property("QStringList", lambda self: self._content, constant=True)