# -*- coding: utf-8 -*-

#from PyQt5.QtCore import *
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QMessageBox


#from qgis.gui import QgsMessageBar, QgsMapToolEmitPoint, QgsRubberBand
from qgis.gui import *
#from qgis.core import QgsWkbTypes, Qgis, QgsPointXY, QgsRectangle, QgsMapLayer, QgsFeatureRequest
from qgis.core import *
from qgis.utils import iface 

#from shapely.geometry import Point, LineString, MultiLineString, Polygon, shape
from shapely.geometry import *

class Retangulo(QgsMapToolEmitPoint): 
           
    def __init__(self, canvas, iface):
        """
        draws a rectangle, then features that intersect this rectangle are added to selection 
        """
        # Store reference to the map canvas
        self.canvas = canvas  

        self.iface = iface        # add iface for work with active layer                
                
        QgsMapToolEmitPoint.__init__(self, self.canvas)
                
        self.rubberBand = QgsRubberBand(self.canvas, geometryType=QgsWkbTypes.LineGeometry)
        self.rubberBand.setColor(QColor(0, 0, 240, 100))
        self.rubberBand.setWidth(1)
        
        self.reset() 
               

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False        
        self.rubberBand.reset( QgsWkbTypes.PolygonGeometry )


    def canvasPressEvent(self, e):
        """
        Method used to build rectangle if shift is held, otherwise, feature select/deselect and identify is done.
        """
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        
        self.showRect(self.startPoint, self.endPoint)
        
    #self.isEmittingPoint is used to build the rubberband on the method on CanvasMoveEvent

            
    def canvasMoveEvent(self, e):
        """
        Used only on rectangle select.
        """
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates( e.pos() )
        self.showRect(self.startPoint, self.endPoint)

   
    def showRect(self, startPoint, endPoint):
        """
        Builds rubberband rect.
        """        
        self.rubberBand.reset( QgsWkbTypes.PolygonGeometry )
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)    # true to update canvas
        self.rubberBand.show()


    def rectangle(self):
        """
        Builds rectangle from self.startPoint and self.endPoint
        """
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():
            return None
        return QgsRectangle(self.startPoint, self.endPoint)

    
    def canvasReleaseEvent(self, e):
        """
        After the rectangle is built, here features are selected.
        """
        self.isEmittingPoint = False

        r = self.rectangle()            #QgsRectangle
        
        if r is not None:
            
            layer = self.iface.activeLayer()   # work with active layer  
                       
            selfeats=[]             # feature included in the box
            fieldselFeats = []      # attribute name    
            attrselFeats = []       # attribute value 

            bbRect = self.canvas.mapSettings().mapToLayerCoordinates(layer, r) 
            for f in layer.getFeatures(QgsFeatureRequest(bbRect)):                  
                selfeats.append( f )                
                fieldsFeats = []
                fieldFeat = f.fields()
                attrFeat = f.attributes()
                attrselFeats.append(attrFeat)
                
                for field in fieldFeat:
                    fieldsFeats.append(field.name())

                fieldselFeats.append(fieldsFeats)
            
            self.rubberBand.hide()
            
            if (len(selfeats) < 2):
                QMessageBox.information(self.iface.mainWindow(), "Info", "At least two lines should be selected.")                 
                return

            # validate attribute name and value
            validateOk = self.validAttr(fieldselFeats, attrselFeats)
            if validateOk == 1:
                QMessageBox.information(self.iface.mainWindow(), "Info", "Features must have same attributes and values")                 
                return

            totfeats = len(selfeats)
            flagx = 0             # control the messageBar
            
            while totfeats > 0:               

                newgeom, indfeat1, indfeat2 = self.calcNewGeom(selfeats, r)

                if newgeom == None:
                    #flagx = 0
                    totfeats = 0
                else: 
                    flagx = 1

                    layer.startEditing()                               
            
                    newgeom.setFields(selfeats[0].fields())
                    for field in fieldselFeats[0]:                                   
                        newgeom.setAttribute(field, selfeats[0][field])                     
      
                    layer.addFeature(newgeom)                    

                    for feat in selfeats:
                        if feat == selfeats[indfeat1]:
                            layer.deleteFeature( feat.id() )
                                                        
                        if feat == selfeats[indfeat2]:
                            layer.deleteFeature( feat.id() )
                                                
                    selfeatsx = list(selfeats)
                    selfeats = []
                    selfeats.append(newgeom)

                    for feat in selfeatsx:
                        if feat == selfeatsx[indfeat1]:                            
                            totfeats = totfeats - 1                            
                        else:
                            if feat == selfeatsx[indfeat2]:                            
                                totfeats = totfeats - 1 
                            else:
                                selfeats.append(feat) 
                                totfeats = totfeats + 1
                  
                                   
            if flagx == 0:
                QMessageBox.information(self.iface.mainWindow(), "Info", "No changes were made.") 
            else:
                layer.triggerRepaint()                                        
                self.iface.messageBar().pushMessage("CIGeoE Merge Multiple Lines", "Merge Multiple Lines done" , level=Qgis.Info, duration=2)




    def validAttr(self, listnames, listvalues):
        valOK = 0  
        
        for i_ind in range(len(listnames)):
            for j_ind in range(len(listnames)):              
                if (i_ind != j_ind):  
                    if len(listnames[i_ind]) == len(listnames[j_ind]):

                        for ii in range(len(listnames[i_ind])):                        
                            if listnames[i_ind][ii] != listnames[j_ind][ii]:                                
                                valOK = 1
                                return valOK
                            else:
                                if listvalues[i_ind][ii] != listvalues[j_ind][ii]:                                    
                                    valOK = 1
                                    return valOK
                    else:
                        valOK = 1
                        return valOK



    def calcNewGeom(self, selfeats, r):
        vertDentro = []  
        ordDentro = [] 
        newFeature = None        
        ordFeat = 0

        for linha in selfeats:
                                         
            verticesArray = linha.geometry().asPolyline()      
            primeiroVertice = verticesArray[0]
            ultimoVertice = verticesArray[len(verticesArray)-1]       
                    
            #  points within the rectangle
            if (r.xMinimum() <= primeiroVertice.x() <= r.xMaximum()) and (r.yMinimum() <= primeiroVertice.y() <= r.yMaximum()) :
                vertDentro.append(primeiroVertice) 
                ordDentro.append(ordFeat) 
            if (r.xMinimum() <= ultimoVertice.x() <= r.xMaximum()) and (r.yMinimum() <= ultimoVertice.y() <= r.yMaximum()) :
                vertDentro.append(ultimoVertice)
                ordDentro.append(ordFeat) 

            ordFeat = ordFeat + 1       

        for i_ind in range(len(vertDentro)):
            for j_ind in range(len(vertDentro)):                

                if (i_ind != j_ind) and (vertDentro[i_ind] == vertDentro[j_ind]):
                    indfeat1 = ordDentro[i_ind]
                    indfeat2 = ordDentro[j_ind]
                    newFeature=QgsFeature()                    
                    newFeature.setGeometry( selfeats[indfeat1].geometry().combine( selfeats[indfeat2].geometry() ) )
                    return newFeature, indfeat1, indfeat2 

        if newFeature is None:           
           return None, None, None 
