#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 import QtCore
from PyQt4.Qt import QSqlQueryModel, QAbstractItemView, \
    QSqlTableModel, QItemSelectionModel, Qt, QTableWidgetItem, QDoubleSpinBox, QSqlQuery, QSortFilterProxyModel, QObject
from feature.AKFeature import AKFeature
from form.AKFormQueryMeasurements import AKFormQueryMeasurements
from model.SavedQueryMeasurementsModel import SavedQueryMeasurementsModel, MEASUREMENT_RESULTS
from view.CheckBoxDelegate import CheckBoxDelegate
from AKSettings import TABLES

class AKFeatureMeasurements(AKFeature):
    '''
    Provides a form to select individual measurements. The selection is for the selected query and a specific 
    set of parameters that can either be selected manually or imposed by the caller of the this class.
    If the measurement value is outside the detection limit range, the limit itself is multiplied by factor that can 
    be set for each base parameter in the listview. Different multiplication factors can be applied if the value 
    is below of above the detection limit. If the value is the result of this multiplication, the column isCalculated will be set to true.
    
    This sub-feature is used by many of the plot and map features.   
    '''
    nextForm = QtCore.pyqtSignal(QObject)
    
    def __init__(self, settings, iface, windowTitle = u'Query Measurements', parent=None):
        super(AKFeatureMeasurements, self).__init__(iface, parent)
        self.normativeId = -1    
        self.availableParams = []    
        self.m_settings = settings
        self.m_text = windowTitle
        self.m_form = AKFormQueryMeasurements(self.iface, self.parent())
        self.m_form.setWindowTitle(self.m_text)
        self.m_form.btnNext.clicked.connect(self.onNext)
        self.m_form.btnSelectParams.clicked.connect(self.onAddSelectedParameters)
        self.m_form.btnDeselectParams.clicked.connect(self.onRemoveSelectedParameters)        
        self.m_form.butRunQuery.clicked.connect(self.onRunQuery)
        self.m_form.btnSelectAllResults.clicked.connect(self.onSelectAllResults)
        self.m_form.btnDeselectAllResults.clicked.connect(self.onDeselectAllResults)
        self.m_form.btnClose.clicked.connect(self.onClose)
        self.m_form.btnActivateResults.clicked.connect(self.activateResults)
        self.m_form.btnDeactivateResults.clicked.connect(self.deActivateResults)
        self.m_form.finished.connect(self.onClose)
        self.m_form.twParamsAll.setColumnHidden(1, True)        
        self.m_form.twParamsAll.setColumnHidden(2, True)
        self.m_form.twParamsAll.setColumnHidden(3, True)
        self.m_form.twParamsSelected.setColumnWidth(0,150)
        self.m_form.twParamsSelected.setColumnWidth(1,70)
        self.m_form.twParamsSelected.setColumnWidth(2,70)
        self.m_form.twParamsSelected.setColumnWidth(3,70)
        self.m_form.twParamsSelected.setColumnHidden(3, True)
        self.queryListModel = None
        self.m_parametersAreImposed = True
        self.defineSQLQueries()

    def imposeParameters(self, parameterInfo):
        if(self.m_parametersAreImposed == True):
            self.m_imposedParameters = parameterInfo
            self.m_form.btnSelectParams.setEnabled(False)
            self.m_form.btnDeselectParams.setEnabled(False)
            self.m_form.twParamsSelected.setEnabled(True)
            self.m_form.twParamsSelected.setSelectionMode(QAbstractItemView.NoSelection)
            self.m_form.twParamsAll.setEnabled(False)
            self.m_form.btnSelectParams.setEnabled(False)
            self.m_form.btnDeselectParams.setEnabled(False)        

    def initialize(self):
        self.m_form.btnNext.setEnabled(False)
        self.clearAllAttributes()
        self.currentDB = self.m_settings.getCurrentDB()
        if(self.currentDB != None):        
            self.queryListModel = QSqlTableModel(self, self.currentDB)        
            self.queryListModel.setTable(self.queryTable)
            self.queryListModel.setEditStrategy(QSqlTableModel.OnFieldChange)
            self.queryListModel.select()
            self.onLoadQueryView()        
            self.loadParameterViews()
            self.m_form.show()
            self.m_form.exec_()
            
    def clearAllAttributes(self):
        self.currentDB = None
        self.currentQueryId = None
        self.queryListModel = None
        self.m_form.tvResults.setModel(QSqlQueryModel(self))
        self.m_form.twParamsSelected.clearContents()
        self.m_form.twParamsSelected.setRowCount(0)
        self.m_form.twParamsAll.clearContents()
        self.m_form.twParamsAll.setRowCount(0)
    
    def onLoadQueryView(self):
        curView = self.m_form.lvQueries
        curView.setModel(self.queryListModel)
        curView.setSelectionBehavior(QAbstractItemView.SelectRows)
        curView.setModelColumn(1)
        curView.selectionModel().selectionChanged.connect(self.onLvQueriesSelectionChanged)
        self.selectFirstInView(curView)

    def updateQueryButton(self):
        if(self.m_form.twParamsSelected.rowCount() > 0):
            self.m_form.butRunQuery.setEnabled(True)
        else:
            self.m_form.butRunQuery.setEnabled(False)
        
    def onAddSelectedParameters(self):
        sel = self.m_form.twParamsAll.selectionModel()
        while(sel.hasSelection()):
            rowId = sel.selectedRows()[0].row() 
            self.moveParameter(self.m_form.twParamsAll, self.m_form.twParamsSelected, rowId)
        self.updateQueryButton()
    
    def onRemoveSelectedParameters(self):
        sel = self.m_form.twParamsSelected.selectionModel()
        while(sel.hasSelection()):
            rowId = sel.selectedRows()[0].row() 
            self.moveParameter(self.m_form.twParamsSelected, self.m_form.twParamsAll, rowId)
        self.updateQueryButton()
    
    def onLvQueriesSelectionChanged(self):
        sel = self.m_form.lvQueries.selectionModel().selection()
        if len(sel.indexes()) < 1:
            return
        index = sel.indexes()[0]
        self.currentQueryId = self.queryListModel.record(index.row()).value("Id")
    
    def loadAllParametersView(self):
        sqlSelAllParams = self.sqlSelAllParams_1
        if len(self.availableParams) > 0:
            sqlSelAllParams += self.sqlSelAllParams_2
            sqlSelAllParams += "(" + ",".join(["'" + x + "'" for x in self.availableParams]) + ") "
        sqlSelAllParams += self.sqlSelAllParams_3
        query = QSqlQuery(self.currentDB)
        query.prepare(sqlSelAllParams)
        query.exec_()
        #print(query.lastQuery())
        self.loadAllParams(query)
    
    def createParameterRow(self, tableWidget, values):
        row = tableWidget.rowCount()
        tableWidget.insertRow(row)
        newItem = QTableWidgetItem(values[0])
        tableWidget.setItem(row, 0, newItem)
        newItem.setFlags(newItem.flags() ^ ~ Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        
        newItem = QDoubleSpinBox(tableWidget)
        newItem.setMinimum(0.0)
        newItem.setValue(values[1])
        tableWidget.setCellWidget(row, 1, newItem)
        
        newItem = QDoubleSpinBox(tableWidget)
        newItem.setMinimum(0.0)
        newItem.setValue(values[2])        
        tableWidget.setCellWidget(row, 2, newItem)
        
        newItem = QTableWidgetItem(values[3])
        newItem.setFlags(newItem.flags() ^ ~ Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        tableWidget.setItem(row,3,newItem)                
    
    def loadAllParams(self, query):
        while query.next():
            parameterName = query.value(0)
            parameterCode = query.value(1)
            values = [parameterName, 1.0, 1.0, parameterCode]
            self.createParameterRow(self.m_form.twParamsAll, values)
        
    def findRowOfParameter(self, widget, column, value):
        index = -1
        if(widget != None):
            numOfRows = widget.rowCount()
            for rowNum in range(numOfRows):
                curItem = widget.item(rowNum, column)
                text = curItem.text()
                if(text == value):
                    index = rowNum
                    break
        return index
    
    def loadParameterViews(self):
        self.loadAllParametersView()
        if (self.m_parametersAreImposed):
            for parameterId in self.m_imposedParameters:
                baseParamId = self.m_imposedParameters[parameterId]["baseParam"]
                rowNum = self.findRowOfParameter(self.m_form.twParamsAll, 3, baseParamId)
                self.moveParameter(self.m_form.twParamsAll, self.m_form.twParamsSelected, rowNum)
        self.updateQueryButton()

    def moveParameter(self, sourceWidget, destinationWidget, rowNumber):
        item = sourceWidget.item(rowNumber, 0)
        parameterName = item.text()
        
        minValue = sourceWidget.cellWidget(rowNumber, 1).value()
        maxValue = sourceWidget.cellWidget(rowNumber, 2).value()
        
        item = sourceWidget.item(rowNumber, 3)
        parameterCode = item.text()

        values = [parameterName, minValue, maxValue, parameterCode]
        self.createParameterRow(destinationWidget, values)        
        sourceWidget.removeRow(rowNumber)
    
    def getSelectedParameters(self):
        outOfRangeParams = dict()
        numOfRows = self.m_form.twParamsSelected.rowCount()
        for rowId in range(numOfRows):
            name = self.m_form.twParamsSelected.item(rowId,0).text()
            minFactor = self.m_form.twParamsSelected.cellWidget(rowId,1).value()
            maxFactor = self.m_form.twParamsSelected.cellWidget(rowId,2).value()
            curId = self.m_form.twParamsSelected.item(rowId,3).text()

            outOfRangeParam = dict()
            outOfRangeParam["name"] = name
            outOfRangeParam["id"] = curId
            outOfRangeParam["min"] = minFactor
            outOfRangeParam["max"] = maxFactor
            outOfRangeParams[curId] = outOfRangeParam
        return outOfRangeParams
   
    def onClose(self):
        self.m_form.tvResults.setModel(QSqlQueryModel(self))
        self.m_form.grpLowerPanel.setEnabled(False)
        self.m_form.close()
        
    def onSelectAllResults(self):
        self.selectAllInView(self.m_form.tvResults, QItemSelectionModel.Select)
    
    def onDeselectAllResults(self):
        self.selectAllInView(self.m_form.tvResults, QItemSelectionModel.Deselect)
        
    def activateResults(self):
        sel = self.m_form.tvResults.selectionModel()
        curModel = self.m_form.tvResults.model()
        for index in sel.selectedRows():
            curModel.setData(index, 1)
            
    def deActivateResults(self):
        sel = self.m_form.tvResults.selectionModel()
        curModel = self.m_form.tvResults.model()
        for index in sel.selectedRows():
            curModel.setData(index, 0)
            
    def hideColumnsIfNecessary(self):
        pass

    def onRunQuery(self):
        self.m_form.grpLowerPanel.setEnabled(True)
        
        outOfRangeParams = self.getSelectedParameters()
        selectedParameters = "(" + ",".join(["'" + x + "'" for x in outOfRangeParams.keys()]) + ")"
        if(self.normativeId == -1):
            sqlSelMeasurements = self.sqlSelMeasurements_1_1 + selectedParameters + self.sqlSelMeasurements_2
        else:
            sqlSelMeasurements = self.sqlSelMeasurements_1_2 + selectedParameters + self.sqlSelMeasurements_2
        query = QSqlQuery(self.currentDB)
        query.prepare(sqlSelMeasurements)
        query.addBindValue(self.currentQueryId)
        if(self.normativeId != -1):
            query.addBindValue(self.normativeId)
        query.exec_()

        myModel = SavedQueryMeasurementsModel()
        myModel.setOutOfRangeParams(outOfRangeParams)
        myModel.setDB(self.currentDB)
        pointsTableInfo = self.m_settings.m_availableTables[TABLES.POINTS]
        myModel.setQuery(query, pointsTableInfo)

        proxyModel = QSortFilterProxyModel()
        proxyModel.setSourceModel(myModel);
        self.m_form.tvResults.setModel(proxyModel)
        self.m_form.tvResults.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.m_form.tvResults.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.m_form.tvResults.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.PointId, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.ParamId, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.BaseParamId, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.MeasurementValue, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.LimitValue, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.UnitId, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.UnitCode, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.XCoord, True)
        self.m_form.tvResults.setColumnHidden(MEASUREMENT_RESULTS.YCoord, True)
        self.m_form.tvResults.setItemDelegateForColumn(MEASUREMENT_RESULTS.Active, CheckBoxDelegate(self.m_form.tvResults))
        self.m_form.tvResults.setItemDelegateForColumn(MEASUREMENT_RESULTS.IsCalculated, CheckBoxDelegate(self.m_form.tvResults))
        self.m_form.tvResults.resizeColumnsToContents()
        self.m_form.tvResults.horizontalHeader().setStretchLastSection(True);
        self.m_form.tvResults.setSortingEnabled(True)
        self.hideColumnsIfNecessary()
        if myModel.rowCount() > 0:
            self.m_form.btnNext.setEnabled(True)
            self.m_form.btnActivateResults.setEnabled(True)
            self.m_form.btnDeactivateResults.setEnabled(True)
            self.m_form.btnDeselectAllResults.setEnabled(True)
            self.m_form.btnSelectAllResults.setEnabled(True)
        else:
            self.m_form.btnNext.setEnabled(False)
            self.m_form.btnNext.setEnabled(False)
            self.m_form.btnActivateResults.setEnabled(False)
            self.m_form.btnDeactivateResults.setEnabled(False)
            self.m_form.btnDeselectAllResults.setEnabled(False)
            self.m_form.btnSelectAllResults.setEnabled(False)
        
    def onNext(self):
        proxyModel = self.m_form.tvResults.model()
        actualModel = proxyModel.sourceModel()
        self.nextForm.emit(actualModel)