from __future__ import absolute_import
from builtins import str
from builtins import range
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from qgis.core import *
from qgis.gui import *
from .Ui_RUSLE_practice import Ui_RUSLE_practice
from . import GdalTools_utils as Utils
from osgeo import gdal
import os
import osgeo
try:
    from PyQt5.QtCore import QString
except ImportError:
    QString = str
from . import GdalTools_utils as Utils
from . import ftools_utils
from processing.core.Processing import Processing

class RUSLE_practice(QDialog, Ui_RUSLE_practice):
    
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)
        
        self.selectButton_dem.clicked.connect(self.fillInputFileEdit)
        self.inputLayerCombo_dem.currentIndexChanged.connect(self.fillInputAttrib)
        self.selectButton_out.clicked.connect( self.fillOutputFileEdit)
        self.buttonAdd.clicked.connect( self.actionAdd)
        self.buttonRemove.clicked.connect( self.actionRemove)
        self.buttonBox.accepted.connect( self.convert)     
        self.buttonAttribute.clicked.connect( self.attributeTable)
        
        # connect help
        #self.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect( self.help)
        
# HELP
    def help(self):
        QMessageBox.about(self, "RUSLE", """<p><b>P factor</b></p> 
        <p><b>Definition</b>: P factor is the ratio which incorporating influences of conservation practices such as contour-ing or terraces 
        to protect the soil (Renard et al., 1997). This values range from 0 to 1. Values equal to 0 or less than 1 are used when the adopted 
        conservation practice reduces soil erosion. Values equal to 1 are adapted when the land is directly cultivated on the slope.The P factor 
        is estimated by using the method adopted by Kumar and Kushwaha (2013) which is based in land cover/land use information. Considering the 
        different type of land use, the P factors are assigned according to the values defined in the literature. The feature button allows to input 
        the shapefile and presents a table with the nomenclature and P factors already defined. The user can modify the factors or import the shapefile 
        attribute table in order to assign other values. The attribute field and the cell size are defined by default but can be modified by the user.  
        As with the C factor, an algorithm from GRASS is used to rasterize the shapefile with the P values assigned.</p>
        <p><b>Method</b></p> 
        <p>Input file = Land use/ Land cover map. </p>
        <p>Parameters = Attribute with the soil occupation and the cell size. Table with the classification and the P factor </p>
        <p>Output file = P factor raster file </p>""")          
        
        
# INPUT VECTOR FILE CLC
    def fillInputFileEdit(self):
        lastUsedFilter = Utils.FileFilter.lastUsedVectorFilter()
        inputFile, encoding = Utils.FileDialog.getOpenFileName(self, self.tr( "Select the input file" ), Utils.FileFilter.allVectorsFilter(), lastUsedFilter, True)
        self.lastEncoding = encoding
        self.loadFields(inputFile)
        self.inputLayerCombo_dem.addItem(inputFile)
        check = QFile(inputFile)    
        
    def fillInputAttrib(self, inputFile):
        self.layer = QgsVectorLayer(self.inputLayerCombo_dem.currentText(), 'inputfile'  , "ogr")
        self.lineAttrib.clear()    
        changedField = ftools_utils.getFieldList(self.layer)
        for f in changedField:
            if f.type() == QVariant.Int or f.type() == QVariant.String or f.type()==QVariant.Double:
                self.lineAttrib.addItem(str(f.name()))   
                
    def loadFields(self, vectorFile = QString()):
        if vectorFile == None:
            return
        try:
            (fields, names) = Utils.getVectorFields(vectorFile)
        except Exception as e:
            QErrorMessage(self).showMessage( str(e) )          
        self.inputLayerCombo_dem.clearEditText()
        ncodec = QTextCodec.codecForName(self.lastEncoding)     
        
    def fillInputFileEdit1(self):
        lastUsedFilter = Utils.FileFilter.lastUsedVectorFilter()
        inputFile, encoding = Utils.FileDialog.getOpenFileName(self, self.tr( "Select the input file" ), Utils.FileFilter.allVectorsFilter(), lastUsedFilter, True)
        self.lastEncoding = encoding
        #self.loadFields(inputFile)
        self.inputLayerCombo_mask.addItem(inputFile)
        check = QFile(inputFile) 
  
  
# ------------------------------ // ------------------------------------ // ----------------------------        
        
# OUTPUT RASTER FILE
    def fillOutputFileEdit(self):
        lastUsedFilter = Utils.FileFilter.lastUsedRasterFilter()
        outputFile = Utils.FileDialog.getSaveFileName(self, self.tr( "Select the raster file to save the results to" ), Utils.FileFilter.allRastersFilter(), lastUsedFilter )
        self.inputLayerCombo_out.setText(outputFile) 
          
# -------------------------------- // --------------------------------- // -------------------------------

# BUTTON ADD AND REMOVE CLASSES
    def actionAdd(self):
        n = self.tableWidget.rowCount()
        self.tableWidget.insertRow(n)
        n = self.tableWidget.rowCount()
        return True
                   
    def actionRemove(self):
        n = self.tableWidget.rowCount()
        for i in range(1,n):
            self.tableWidget.removeRow(n-1)
        n = self.tableWidget.rowCount()
        return True
   
   # ---------------------------------- // ----------------------------- // ------------------------------------
    
    def attributeTable(self):
        if self.inputLayerCombo_dem.currentText()!='':
            inputLayer = self.inputLayerCombo_dem.currentText()
            # layer information
            layer = QgsVectorLayer(inputLayer, inputLayer , "ogr")
            # attribute
            Elevation = self.lineAttrib.currentText()        
            fields = layer.fields()
            field_names = [field.name() for field in fields]
            n = len(field_names)
            lista_attrib = []
            for i in range(0,n):
                f = field_names[i]
                if f==str(Elevation):
                    number = i
                    for feat in layer.getFeatures():
                        attrb = feat.attributes()
                        attribute_read = attrb[number] #reads the attribute one by one
                        lista_attrib = lista_attrib + [str(attribute_read)]
            # list of description on attribute table of shapefile
            lista_attributes = lista_attrib   
            len_attb = len(lista_attributes)
                
            # delete duplicate names
            lista_att_dupl = []
            [lista_att_dupl.append(i) for i in lista_attributes if not i in lista_att_dupl]        
            
            # save the description of shapefile in tool table and delete all the other information, such as indexes and other descriptions
            numberRows = int(self.tableWidget.rowCount())
            self.tableWidget.clearContents()
            
            for j in range(0,len(lista_att_dupl)):
                self.tableWidget.setItem(j, 0, QTableWidgetItem(lista_att_dupl[j]))
                
            # remove the lines with no values
            for a in range(0, numberRows):
                if self.tableWidget.item(a,0)== None:
                    self.actionRemove()
                    
        if self.inputLayerCombo_dem.currentText()=='':
            inputLayer = self.inputLayerCombo_soil.currentText()
            # layer information
            layer = QgsVectorLayer(inputLayer, inputLayer , "ogr")
            # attribute
            Elevation = self.lineAttrib.currentText()        
            fields = layer.fields()
            field_names = [field.name() for field in fields]
            n = len(field_names)
            lista_attrib = []
            for i in range(0,n):
                f = field_names[i]
                if f==str(Elevation):
                    number = i
                    for feat in layer.getFeatures():
                        attrb = feat.attributes()
                        attribute_read = attrb[number] #reads the attribute one by one
                        lista_attrib = lista_attrib + [str(attribute_read)]
            # list of description on attribute table of shapefile
            lista_attributes = lista_attrib   
            len_attb = len(lista_attributes)
                
            # delete duplicate names
            lista_att_dupl = []
            [lista_att_dupl.append(i) for i in lista_attributes if not i in lista_att_dupl]        
            
            # save the description of shapefile in tool table and delete all the other information, such as indexes and other descriptions
            numberRows = int(self.tableWidget.rowCount())
            self.tableWidget.clearContents()
           
            for j in range(0,len(lista_att_dupl)):
                self.tableWidget.setItem(j, 0, QTableWidgetItem(lista_att_dupl[j]))
                
            # remove the lines with no values
            for a in range(0, numberRows):
                if self.tableWidget.item(a,0)== None:
                    self.actionRemove()            
   
    def convert(self):
        gdal.AllRegister() 
        inputLayer_dem = self.inputLayerCombo_dem.currentText()
        layer = QgsVectorLayer(inputLayer_dem, inputLayer_dem , "ogr")
        vectorlayer_vector =  layer.dataProvider()
        # extent
        extent_rect = vectorlayer_vector.extent()
        xmin = extent_rect.xMinimum()
        xmax = extent_rect.xMaximum()
        ymin = extent_rect.yMinimum()
        ymax = extent_rect.yMaximum()
        extent = str(xmin) + "," + str(xmax) + "," + str(ymin) + "," + str(ymax)
        # attribute
        Elevation = self.lineAttrib.currentText()
        # cellsize
        cellSize = int(self.linePix.value())
        outPath = self.inputLayerCombo_out.text() 
        # read fields and add a new column with the factor C
        fields = layer.fields()
        new_field = QgsField("Fator_C", QVariant.Double)
        layer_new = vectorlayer_vector.addAttributes([new_field])
        layer.updateFields()
        newFieldIndex = vectorlayer_vector.fieldNameIndex(new_field.name())
        allAttrs = vectorlayer_vector.attributeIndexes()
        # editing the new column
        numberRows = int(self.tableWidget.rowCount())
        numberColumns = int(self.tableWidget.columnCount())
        classes = ''
        lista = []
        for i in range(0,numberRows):
            for j in range(0,numberColumns):
                self.line = self.tableWidget.item(i,j)
                lista = lista + [str(self.line.text())]
               
        # list of description on tool table
        lista_table = lista
        
        field_names = [field.name() for field in fields]
        n = len(field_names)
        lista_attrib = []
        for i in range(0,n):
            f = field_names[i]
            if f==str(Elevation):
                number = i
                for feat in layer.getFeatures():
                    attrb = feat.attributes()
                    attribute_read = attrb[number]
                    lista_attrib = lista_attrib + [str(attribute_read)]
        # list of description on attribute table of shapefile
        lista_attributes = lista_attrib   
       
        # obtain the indexes of the description of shapefile attribute table (nao repetidas)
        description_common = set(lista_attributes).intersection(lista_table)
        listDescription = list(description_common)
        
        listElem = []
        listElements = []
        for j in range(0,len(listDescription)):
            elem = lista_table.index(listDescription[j])
            listElements = listElements + [elem]
            
            elem_index = lista_table[int(elem+1)]
            listElem = listElem + [float(elem_index)]
      
        for l in range(0, len(listElem)):
            layer.startEditing()
            exp = QgsExpression(str(listElem[l]))
            #exp.prepare(fields)
            elemDescription = lista_table[listElements[l]]
            # aguas interiores, culturas temporarias, ...
            for f in layer.getFeatures():
                # get attributes of column defined by the user
                attrb_elem = f[number]
                if attrb_elem==elemDescription: 
                    f[newFieldIndex] = exp.evaluate()
                    layer.updateFeature(f)  
            layer.commitChanges()   
        list_attrb_newField = []
        for features in layer.getFeatures():
            attrb_newField = features.attributes()
            attrb_newField_read = attrb_newField[number+1]
            # novo atributo
           
        # update and read the new field
        fieldsNew = layer.fields()
        field_names_new = [newField.name() for newField in fieldsNew]        
        parameter_indexes = field_names_new[newFieldIndex]
        
        Processing.initialize()
        #Processing.runAlgorithm("grass7:v.to.rast.attribute", None, inputLayer_dem, 0, parameter_indexes, extent, cellSize, -1.0, 0.0001, outPath)
        Processing.runAlgorithm("grass7:v.to.rast", {
            'input': inputLayer_dem,
            'type': [0, 1, 3], 'where': '', 'use': 0, 'attribute_column': parameter_indexes, 'rgb_column': None,
            'label_column': None, 'value': 1, 'memory': 300, 'output': outPath,
            'GRASS_REGION_PARAMETER': None, 'GRASS_REGION_CELLSIZE_PARAMETER': cellSize, 'GRASS_RASTER_FORMAT_OPT': '',
            'GRASS_RASTER_FORMAT_META': '', 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
            'GRASS_MIN_AREA_PARAMETER': 0.0001})

        # add result into canvas
        file_info = QFileInfo(outPath)
        if file_info.exists():
            layer_name = file_info.baseName()
        else:
            return False
        rlayer_new = QgsRasterLayer(outPath, layer_name)
        # add result into canvas
        QgsProject.instance().addMapLayer(rlayer_new)
        self.canvas = QgsMapCanvas()
        # self.canvas.scene().addItem(vdlayer)
        QgsProject.instance().addMapLayer(rlayer_new)
        QMessageBox.information(self, self.tr( "Finished" ), self.tr( "RUSLE Factor P completed." ) )
       
     