from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtCore, QtGui
from qgis.core import *
from qgis.gui import *
from .Ui_RUSLE_cover import Ui_RUSLE_cover
import GdalTools_utils as Utils
from osgeo import gdal
import os
import osgeo
try:
    from PyQt5.QtCore import QString
except ImportError:
    QString = str
import GdalTools_utils as Utils
import ftools_utils
from processing.core.Processing import Processing

SYS_DIR  = "C:/OSGeo4W64/apps"
QGIS_DIR = os.path.join(SYS_DIR, 'qgis')

class RUSLE_cover(QDialog, Ui_RUSLE_cover):
    
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)
        
        self.selectButton_geo.clicked.connect(self.fillInputFileEdit)
        self.selectButton_soil.clicked.connect(self.fillInputFileEdit1)
        self.buttonBox.accepted.connect(self.convert)
        self.selectButton_out.clicked.connect(self.fillOutputFileEdit)
        self.inputLayerCombo_geo.currentIndexChanged(QString).connect(self.fillInputAttrib)
        self.inputLayerCombo_soil.currentIndexChanged(QString).connect(self.fillInputAttrib1)
        self.buttonPDF.clicked.connect(self.pdf)
        self.buttonAttribute.clicked.connect(self.attributeTable)
        self.buttonAdd.clicked.connect(self.actionAdd)
        self.buttonRemove.clicked.connect(self.actionRemove)
        
        # connect help
        #self.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.help)
        
# HELP
    def help(self):
        QMessageBox.about(self, "RUSLE", """<p><b>C factor</b></p> 
        <p><b>Definition</b>:C factor is used to infer about cropping and management practices effects on erosion rates. C value is equal to 1 for bare 
        soil and decreased with increasing soil cover, which implies less soil erosion. 
        In order to estimate this factor, different approaches have been used. Image classification based is commonly used (Arekhi et al., 2012; Jiang et al., 
        2012; Xu et al., 2012; Alexakis et al., 2013), as well as CLC (Corine Land Cover) map (Fagnano et al., 2012; Kumar et al., 2013) and several tables were 
        developed and published for Portugal mainland (Pimenta, 1998). The inputs to estimate the C factor can be obtained in the CLC map or the COS data and the 
        user should assign the C factor (0 to 1 scale) values to each land use class according to tables provided by the application. These tables can be modified 
        according to the rules for each country or region. The process to access and open pdf files is the same considered for the K factor. To simplify the way of 
        assigning C factor values, the application allows to import the shapefile attribute table into the application table and the user assigns the C values, 
        manually. Finally, through v.to.rast.attribute algorithm, the shapefile is rasterized. Other options, as Add rows or Remove rows, are improved in the 
        application, so the user can manipulate the table.</p>
        <p><b>Method</b></p> 
        <p>Input file = Corine Land Cover or COS (in case of Portugal). </p>
        <p>Parameters = Attribute with the soil occupation and the cell size. Table with the classification and the C factor </p>
        <p>Output file = C 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_geo.addItem(inputFile)
        check = QFile(inputFile)    
        
    def fillInputAttrib(self, inputFile):
        self.layer = QgsVectorLayer(unicode(self.inputLayerCombo_geo.currentText()).encode('utf8'), 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(unicode(f.name()))   
                
    def loadFields(self, vectorFile = QString()):
        if vectorFile == None:
            return
        try:
            (fields, names) = Utils.getVectorFields(vectorFile)
        except Exception, e:
            QErrorMessage(self).showMessage( str(e) )          
        self.inputLayerCombo_geo.clearEditText()
        ncodec = QTextCodec.codecForName(self.lastEncoding)    
        
# INPUT VECTOR FILE COS        
    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.loadFields1(inputFile)
        self.inputLayerCombo_soil.addItem(inputFile)
        check = QFile(inputFile)    
            
    def fillInputAttrib1(self, inputFile):
        self.layer = QgsVectorLayer(unicode(self.inputLayerCombo_soil.currentText()).encode('utf8'), 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(unicode(f.name()))   
                
    def loadFields1(self, vectorFile = QString()):
        if vectorFile == None:
            return
        try:
            (fields, names) = Utils.getVectorFields(vectorFile)
        except Exception, e:
            QErrorMessage(self).showMessage( str(e) )          
        self.inputLayerCombo_soil.clearEditText()
        ncodec = QTextCodec.codecForName(self.lastEncoding)    
        
    
# ------------------------------ // ------------------------------------ // ----------------------------
       
   # 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 )
        if outputFile==None:
            return
        Utils.FileFilter.setLastUsedRasterFilter(lastUsedFilter)
        self.outputFormat = Utils.fillRasterOutputFormat( lastUsedFilter, outputFile )
        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
# -------------------------------------------------------------------------------------------------------------

# PDF CONNECTION

    def pdf(self):
        ## access to pdf files 
        import subprocess
        pdf = os.path.join(QGIS_DIR, 'python\\plugins\\RUSLE\\Table C Factor.pdf')
        subprocess.Popen([pdf],shell=True)  
        
# ------------------------------------------------------------------------------------------------------------
        
# CONVERT SHAPEFILE TO RASTER
    def convert(self):    
        self.buttonBox.button(QDialogButtonBox.Ok).setDefault(False)
        # if clc exists
        if self.inputLayerCombo_geo.currentText()!='':
            inputLayer = self.inputLayerCombo_geo.currentText()
            #inputLayer = "C:/Users/Lia/Desktop/Artigos/Artigo_RUSLE/Dados/meteo_rain_days10"
            # layer information
            layer = QgsVectorLayer(unicode(inputLayer).encode('utf8'), inputLayer , "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.pendingFields() 
            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
            # [xistos argilosos, argilitos, 2, rocha metamorfica/ignea, 3, ...]
            
            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)
            # [lista nao repetida]
            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(f)
                        layer.updateFeature(f)  
                layer.commitChanges()   
            list_attrb_newField = []
            for features in layer.getFeatures():
                attrb_newField = features.attributes()
                attrb_newField_read = attrb_newField[number+1]

            # update and read the new field
            fieldsNew = layer.pendingFields()
            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, 0, parameter_indexes, extent, cellSize, -1.0, 0.0001, outPath)
            
            
            # 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)
            if rlayer_new.isValid():
                QgsMapLayerRegistry.instance().addMapLayer(rlayer_new)
                #layer = QgsMapCanvasLayer(rlayer_new)
                #layerList = [layer]
                #extent = self.iface.canvas.setExtent(rlayer_new.extent())
                #self.iface.canvas.setLayerSet(layerList)
                #self.iface.canvas.setVisible(True)         
                return True
            else:
                return False    
            QMessageBox.information(self, self.tr( "Finished" ), self.tr( "Aquifer media completed." ) )  
           
        # if COS exist 
        if self.inputLayerCombo_geo.currentText()=='':
            inputLayer = self.inputLayerCombo_soil.currentText()
            # layer information
            layer = QgsVectorLayer(unicode(inputLayer).encode('utf8'), inputLayer , "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.pendingFields() 
            new_field = QgsField("Fator_C", QVariant.Double, "double", 5, 3)
            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
            description_common = set(lista_attributes).intersection(lista_table)
            listDescription = list(description_common)
            
            # [xistos argilosos, argilitos, till glaciar]
            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]]
               
                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(f)
                        layer.updateFeature(f)  
                layer.commitChanges()   
            list_attrb_newField = []
            for features in layer.getFeatures():
                attrb_newField = features.attributes()
                attrb_newField_read = attrb_newField[number+1]
               
            # update and read the new field
            fieldsNew = layer.pendingFields()
            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, 0, parameter_indexes, extent, cellSize, -1.0, 0.0001, outPath)
            
            # 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)
            if rlayer_new.isValid():
                QgsMapLayerRegistry.instance().addMapLayer(rlayer_new)
                #layer = QgsMapCanvasLayer(rlayer_new)
                #layerList = [layer]
                #extent = self.iface.canvas.setExtent(rlayer_new.extent())
                #self.iface.canvas.setLayerSet(layerList)
                #self.iface.canvas.setVisible(True)         
                return True
            else:
                return False    
            QMessageBox.information(self, self.tr( "Finished" ), self.tr( "Aquifer media completed." ) )              

    def attributeTable(self):
        if self.inputLayerCombo_geo.currentText()!='':
            inputLayer = self.inputLayerCombo_geo.currentText()
            # layer information
            layer = QgsVectorLayer(unicode(inputLayer).encode('utf8'), inputLayer , "ogr")     
            # attribute
            Elevation = self.lineAttrib.currentText()        
            fields = layer.pendingFields() 
            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, QtGui.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_geo.currentText()=='':
            inputLayer = self.inputLayerCombo_soil.currentText()
            # layer information
            layer = QgsVectorLayer(unicode(inputLayer).encode('utf8'), inputLayer , "ogr")     
            # attribute
            Elevation = self.lineAttrib.currentText()        
            fields = layer.pendingFields() 
            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, QtGui.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()            
            