#coding=utf-8
#Copyright (C) 2015 IDAEA-CSIC
#
#This program is free software; you can redistribute it and/or modify it under the terms of the 
#GNU General Public License as published by the Free Software Foundation; either version 2 of the License, 
#or (at your option) any later version. This program is distributed in the hope that it will be useful, but 
#ITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
#PURPOSE. See the GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License along with this program; if not, write to 
#the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
'''
:copyright: Copyright (C) 2015 IDAEA-CSIC
:authors: V. Velasco Mansilla, L.M. de Vries, A. Nardi, R. Criollo, E. Vázquez Suñé
:contact: enric.vazquez@idaea.csic.es
:license: GPL General Public License, version 2 or any later version (http://opensource.org/licenses/GPL-2.0)
'''
from PyQt4.Qt import Qt, QAbstractTableModel, QModelIndex, QBrush, QColor
from model.SavedQueryMeasurementsModel import MEASUREMENT_RESULTS
from PyQt4 import QtCore

class SamplesMeasurementsModel(QAbstractTableModel):
    def __init__(self, parent=None): 
        super(SamplesMeasurementsModel, self).__init__(parent)
        self.fixedHeaders = ["PointId", "Point", "Coordinate X", "Coordinate Y", "Campaign", "Sample", "Date"]
        self.fixedFields = [MEASUREMENT_RESULTS.PointId,
                            MEASUREMENT_RESULTS.Point,
                            MEASUREMENT_RESULTS.XCoord,
                            MEASUREMENT_RESULTS.YCoord,
                            MEASUREMENT_RESULTS.Campaign, 
                            MEASUREMENT_RESULTS.Sample, 
                            MEASUREMENT_RESULTS.SampleDate]
        self.uniqueField = MEASUREMENT_RESULTS.Sample
        
        self.COLUMNS = {}
        self.headers = []
        # groups distinct parameterIds by baseParam:
        # allParams { "baseParam1" : { paramId1 : {id: paramId1, unit: unit, unitId:unitId}, 
        #                              paramId2 : {id: paramId1, unit: unit, unitId:unitId},...
        #                            }
        #           }
        self.allParams = {}
        self.allParamsOrder = []
        
        # column meta-data:
        # columnsFixed { "Point" : {"column":0..},
        # columnsMeasurement { "paramId1" : {"column":4, "baseParam" : "N535", unit: unit, unitId:unitId...},
        #                      "paramId2" : {"column":5, "baseParam" : "N535", unit: unit, unitId:unitId...},...}
        # columnsCustom { "customParam" : {"column":5..},
        self.columnsFixed = {}
        self.columnsMeasurement = {}
        self.columnsCustom = {}
        
        self.numberOfColumns = 0
        self.numberOfFixedColumns = 0
        self.numberOfMeasurementCols = 0
        self.numberOfCustomCols = 0
        
        # Actual data storage
        self.sampleMeasurements = []
        self.customColumData = []
        
        self.addFixedColumns()        
        
    def setInitialData(self, tableModel):
        self.allParams = {}
        self.retrieveMeasurementColumnParameters(tableModel)
        self.retrieveMeasurements(tableModel)
        
    def addFixedColumns(self):
        self.numberOfFixedColumns = len(self.fixedHeaders)
        column = 0
        for i in range(len(self.fixedHeaders)):
            name = self.fixedHeaders[i]
            self.columnsFixed.setdefault(name, {})["column"] = column
            self.COLUMNS[name] = column
            column += 1
        self.headers += self.fixedHeaders
    
    def retrieveMeasurementColumnParameters(self, tableModel):
        # get all distinct parameterIds grouped by baseParam
        numOfMeasurements = tableModel.rowCount()
        for measurementId in range(numOfMeasurements):
            isActive = tableModel.index(measurementId, MEASUREMENT_RESULTS.Active).data()
            baseParam = tableModel.index(measurementId, MEASUREMENT_RESULTS.BaseParamId).data()
            paramId = tableModel.index(measurementId, MEASUREMENT_RESULTS.ParamId).data()
            paramName = tableModel.index(measurementId, MEASUREMENT_RESULTS.Parameter).data()
            unit = tableModel.index(measurementId, MEASUREMENT_RESULTS.Unit).data()
            unitCode = tableModel.index(measurementId, MEASUREMENT_RESULTS.UnitCode).data()
            unitId = tableModel.index(measurementId, MEASUREMENT_RESULTS.UnitId).data()
            if(isActive):
                self.allParams.setdefault(baseParam, {})[paramId] = {"id" : paramId,
                                                                     "paramName" : paramName, 
                                                                     "unit" : unit,
                                                                     "unitCode": unitCode,
                                                                     "unitId": unitId}

        # assign column index
        column = 0
        measurementsHeaders = []
        for curBaseParam in self.allParams:
            # Convert the set of all parameterIds to a list to maintain a specific order 
            for curParamId in self.allParams[curBaseParam]:
                self.allParamsOrder.append(curParamId)
                self.columnsMeasurement.setdefault(curParamId, {})["column"] = self.numberOfFixedColumns + column
                self.columnsMeasurement[curParamId]["baseParam"] = curBaseParam
                self.columnsMeasurement[curParamId]["paramName"] = self.allParams[curBaseParam][curParamId]["paramName"]
                self.columnsMeasurement[curParamId]["unit"] = self.allParams[curBaseParam][curParamId]["unit"] 
                self.columnsMeasurement[curParamId]["unitCode"] = self.allParams[curBaseParam][curParamId]["unitCode"]
                self.columnsMeasurement[curParamId]["unitId"] = self.allParams[curBaseParam][curParamId]["unitId"]
                self.COLUMNS[curParamId] = self.numberOfFixedColumns + column
                measurementsHeaders.append(self.columnsMeasurement[curParamId]["paramName"] + " (" + self.columnsMeasurement[curParamId]["unit"]  +")")
                column += 1
        self.numberOfMeasurementCols = len(self.columnsMeasurement)
        self.headers += measurementsHeaders
        self.numberOfColumns = self.numberOfFixedColumns + self.numberOfMeasurementCols 

    def retrieveMeasurements(self, tableModel):
        lastSample = None
        numOfMeasurements = tableModel.rowCount()
        for measurementId in range(numOfMeasurements):
            isActive = tableModel.index(measurementId, MEASUREMENT_RESULTS.Active).data()
            if(isActive):
                sample = tableModel.index(measurementId, self.uniqueField).data()
                # check if we are in a new sample
                if(lastSample != sample):
                    lastSample = sample
                    fixedValues = []
                    for field in self.fixedFields:
                        value = tableModel.index(measurementId, field).data()
                        fixedValues.append(value)
                    sampleValues = fixedValues + [None] * self.numberOfMeasurementCols
                    self.sampleMeasurements.append(sampleValues)
                    self.customColumData.append([])
                    
                paramId = tableModel.index(measurementId, MEASUREMENT_RESULTS.ParamId).data()
                value = tableModel.index(measurementId, MEASUREMENT_RESULTS.Value).data()
#                 actualColumn = self.numberOfFixedColumns + self.columnsMeasurement[paramId]["column"]
                actualColumn = self.COLUMNS[paramId]
                self.sampleMeasurements[-1][actualColumn] = value
        
    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.headers[section]
        return super(SamplesMeasurementsModel, self).headerData(section, orientation, role)

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

    def columnCount(self, parent=QModelIndex()):
        return self.numberOfColumns
    
    def addColumn(self, parameterId, paramName, baseParam, unit, unitCode, unitId, name, label=""):
        column = self.numberOfFixedColumns + self.numberOfMeasurementCols + self.numberOfCustomCols
        self.columnsCustom.setdefault(parameterId, {})["column"] = column
        self.columnsCustom[parameterId]["baseParam"] = baseParam
        self.columnsCustom[parameterId]["paramName"] = name
        self.columnsCustom[parameterId]["unit"] = unit
        self.columnsCustom[parameterId]["unitCode"] = unitCode
        self.columnsCustom[parameterId]["unitId"] = unitId
        self.COLUMNS[parameterId] = column
        if label == "":
            if unitCode == "UNK":
                header = name
            else:
                header = name + " (" + unit + ")"
        else:
            header = label
        self.headers.append(header)
        self.numberOfCustomCols += 1
        self.numberOfColumns += 1
        for row in range(len(self.customColumData)):
            self.customColumData[row].append(None)
            
            
    def addSimpleColumn(self, header):
        column = self.numberOfFixedColumns + self.numberOfMeasurementCols + self.numberOfCustomCols 
        self.columnsCustom.setdefault(header, {})["column"] = column
        self.columnsCustom[header]["paramName"] = header 
        self.COLUMNS[header] = column 
        self.headers.append(header)
        self.numberOfCustomCols += 1
        self.numberOfColumns += 1
        for row in range(len(self.customColumData)):
            self.customColumData[row].append(None)
    
    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        if role == Qt.DisplayRole:
            numOfNonCustomColumns = self.numberOfColumns - self.numberOfCustomCols  
            if(index.column() >= numOfNonCustomColumns):
                column = index.column() - numOfNonCustomColumns
                return self.customColumData[index.row()][column] 
            return self.sampleMeasurements[index.row()][index.column()]   
        
        elif role == Qt.BackgroundRole:
            if "valid" in self.COLUMNS:
                isValid = self.data(self.index(index.row(), self.COLUMNS["valid"]), Qt.DisplayRole)
                if not isValid:
                    return QBrush(QColor("#F0F0F0"))
                else:
                    return None
        return super(SamplesMeasurementsModel, self).data(index, role)

    def setData(self, index, value, role=Qt.EditRole):
        if(not index or not index.isValid()):
            return False
        numOfNonCustomColumns = self.numberOfColumns - self.numberOfCustomCols
        if(index.column() >= numOfNonCustomColumns):
            column = index.column() - numOfNonCustomColumns
            self.customColumData[index.row()][column] = value
            self.dataChanged.emit(self.index(index.row(), 0), self.index(index.row(), self.numberOfColumns-1))
            return True
        return False
        
    def reset(self):
        self.query().exec_()
        
    def getNumberOfColumns(self):
        return (self.numberOfColumns, self.numberOfFixedColumns, self.numberOfMeasurementCols, self.numberOfCustomCols)
    
    def getMeasurementColumnInfo(self):
        return self.columnsMeasurement
    
    def flags(self, index):        
        if not index.isValid():
            return QtCore.Qt.NoItemFlags
        
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def getCustomColumns(self):
        return self.columnsCustom