# -*- coding: utf-8 -*-
"""
/***************************************************************************
 MitiConnect
                                 A QGIS plugin
 MitiConnect integrates ecological Connectivity in Mitigation Hierarchy
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2021-08-25
        git sha              : $Format:%H$
        copyright            : (C) 2021 by INRAE
        email                : mathieu.chailloux@inrae.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import sys

from qgis.PyQt.QtCore import Qt

from ..qgis_lib_mc.abstract_model import DictItem, DictModel, AbstractConnector

class ClassItem(DictItem):

    INIT_VAL = 'INIT_VAL'
    NEW_VAL = 'NEW_VAL'
    ORIGIN = 'ORIGIN'
    DESCRIPTION = 'DESCRIPTION'
    
    FIELDS = [ ORIGIN, INIT_VAL, NEW_VAL, DESCRIPTION ]
    
    def __init__(self,dict,pluginModel=None,feedback=None):
        # castDict = {
            # self.INIT_VAL : str(dict[self.INIT_VAL]),
            # self.NEW_VAL : str(dict[self.NEW_VAL]),
            # self.ORIGIN : dict[self.ORIGIN],
            # self.DESCRIPTION : dict[self.DESCRIPTION] }
        # super().__init__(castDict,feedback=feedback)
        super().__init__(dict,feedback=feedback)    
        
    @classmethod
    def fromDict(cls,dict,feedback=None):
        return cls(dict,feedback=feedback)
        
    def getInitVal(self):
        return self.dict[self.INIT_VAL]
    def getNewVal(self):
        return self.dict[self.NEW_VAL]
    def getOrigin(self):
        return self.dict[self.ORIGIN]
    def getDescription(self):
        return self.dict[self.DESCRIPTION]
        
    def setNewVal(self,newVal):
        self.dict[self.NEW_VAL] = newVal
        
    def equals(self,other):
        # self.feedback.pushDebugInfo("equals")
        res = ((self.getOrigin() == other.getOrigin()) and (self.getInitVal() == other.getInitVal()))
        if res:
            self.feedback.pushDebugInfo("equals {} -- {} = {}".format(self.dict,other.dict,res))
        return res


class ClassModel(DictModel):

    def __init__(self, pluginModel):
        itemClass = getattr(sys.modules[__name__], ClassItem.__name__)
        super().__init__(itemClass,feedback=pluginModel.feedback)
        self.pluginModel = pluginModel
        
    # @classmethod
    # def fromDict(cls,dict,feedback=None):
        # return cls(dict,feedback=feedback)
        
    def addRow(self,origin,initVal,newVal,descr=""):
        d = { ClassItem.INIT_VAL : str(initVal),
              ClassItem.NEW_VAL : str(newVal),
              ClassItem.ORIGIN : origin,
              ClassItem.DESCRIPTION : descr }
        item = ClassItem(d,feedback=self.feedback)
        self.addItem(item)
        self.pluginModel.frictionModel.addRowFromClassItem(item)
        self.layoutChanged.emit()
        
    def addRowFromValues(self,origin,values):
        freeVals = self.pluginModel.frictionModel.getFreeVals(len(values))
        for initVal, newVal in zip(values,freeVals):
            self.addRow(origin,initVal,newVal)
        # self.layoutChanged.emit()
        
    def getItemsFromOrigin(self,origin):
        items = [i for i in self.items if i.getOrigin() == origin]
        return items
    def getItemFromOrigin(self,origin):
        items = self.getItemsFromOrigin(origin)
        nbItems = len(items)
        if nbItems == 0:
            return None
        elif nbItems == 1:
            return items[0]
        else:
            self.feedback.pushDebugInfo("items = {}".format([i.getInitVal() for i in items]))
            self.feedback.internal_error("Multiple matching items for origin {} in {}".format(origin,items))
    def getItemFromOriginAndVal(self,origin,initVal):
        for i in self.items:
            if i.getOrigin() == origin and i.getInitVal() == initVal:
                return i
        self.feedback.internal_error("No class item found matching origin {} and value {}".format(
            origin,initVal))         
            
    def getItemReclassVal(self,item):
        try:
            newVal = int(item.getNewVal())
        except ValueError:
            newVal = self.pluginModel.nodataVal
        return newVal
    
    def removeItemsWithOrigin(self,origin):
        self.feedback.pushDebugInfo("removeItemsWithOrigin1 {}".format(len(self.items)))
        self.items = [ i for i in self.items if i.dict[ClassItem.ORIGIN] != origin ]
        self.feedback.pushDebugInfo("removeItemsWithOrigin2 {}".format(len(self.items)))
        self.layoutChanged.emit()
        
    # Build table parameter for alg reclassifyByTable [min1, max1, val1, min2, ...]
    def getReclassTable(self,name):
        table = []
        for i in self.items:
            if i.getOrigin() == name:
                inVal = i.getInitVal()
                newVal = self.getItemReclassVal(i)
                line = [inVal, inVal, newVal ]
                table.extend(line)
        return table
    def getReclassDict(self,name):
        table = {}
        for i in self.items:
            # if i.getOrigin() == name:
                # table[i.getInitVal()] = i.getNewVal()
            if i.getOrigin() == name:
                inVal = i.getInitVal()
                newVal = self.getItemReclassVal(i)
                table[inVal] = newVal
        return table
        
    def renameOrigin(self,oldName,newName):
        self.renameFieldValue(ClassItem.ORIGIN,oldName,newName)
    def removeFromOrigin(self,origin):
        self.items = [i for i in self.items if i.getOrigin() != origin]
        self.layoutChanged.emit()
        
    def updateFromScenario(self,scItem):
        scName = scItem.getName()
        self.feedback.pushDebugInfo("updateFromScenario1 " + str(scName))
        self.feedback.pushDebugInfo("updateFromScenario4 " + str(len(self.items)))
        if scItem.isInitialState():
            pass
        elif scItem.isLanduseMode():
            pass
        elif scItem.isFixedMode():
            burnVal = scItem.getBurnVal()
            self.addRow(scName,"",burnVal)
        elif scItem.isValueMode():
            if not scItem.values:
                self.feedback.internal_error("No field value for {}".format(scItem))
            for val in scItem.values:
                try:
                    newVal = int(val)
                except TypeError:
                    newVal = self.pluginModel.frictionModel.getFreeVal()
                self.addRow(scName,val,newVal)
        else:
            self.feedback.pushDebugInfo("Unexpected mode for scenario {}".format(scItem))
        self.layoutChanged.emit()
        self.feedback.pushDebugInfo("updateFromScenario5 " + str(len(self.items)))
        self.pluginModel.frictionModel.updateFromImports()
        
    def flags(self, index):
        baseFlags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
        if index.column() in [2,3]:
            baseFlags = baseFlags | Qt.ItemIsEditable
        return baseFlags
        
        
    # FIELDS = [ INPUT, MODE, VALUE, STATUS ]
    def getHeaderString(self,col):
        h = [self.tr('Origin'),
            self.tr('Initial value'),
            self.tr('New value'),
            self.tr('Description')]
        return h[col]
        
class ClassConnector(AbstractConnector):
    
    def __init__(self,dlg,classModel):
        self.dlg = dlg
        self.feedback = classModel.feedback
        super().__init__(classModel,self.dlg.classView)
        
    def connectComponents(self):
        super().connectComponents()
        print("connectComponents")
        # self.model.layoutChanged.connect(self.model.pluginModel.frictionModel.updateFromImports)
        self.model.dataChanged.connect(self.onItemUpdated)
        
    def onItemUpdated(self,index):
        rowIdx, colIdx = index.row(), index.column()
        self.feedback.pushDebugInfo("onItemUpdated {} {}".format(rowIdx,colIdx))
        classItem = self.model.getNItem(rowIdx)
        self.model.pluginModel.frictionModel.updateFromClassItem(classItem)
        self.model.pluginModel.importModel.updateFromClassItem(classItem)
        