# -*- coding: utf-8 -*-
"""
/***************************************************************************
 c3d
                                 A QGIS plugin
 Civil 3D Exchange Tools
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2020-04-15
        git sha              : $Format:%H$
        copyright            : (C) 2020 by jorgealmerio
        email                : jorgealmerio@yahoo.com.br
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QApplication, QProgressBar, QToolButton, QMenu, QGroupBox

# Initialize Qt resources from file resources.py
from .resources import *
# Import the code for the dialog
from .c3d_dialog import c3dDialog
import os.path
from .c3d_00Common import *
from .c3d_xml import *
import traceback

class c3d(object):
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'c3d_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&C3D')        

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None
        
        self.PVsTipos =[]
        self.progress = None
        self.progressMessageBar = None
        self.cancelButton = None

        #External class references
        self.Common = c3d_Common()
    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('c3d', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        add_to_ToolButton=False,
        defaultToolButton=False,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)
        
        if add_to_ToolButton:
            m = self.menuButton.menu()
            m.addAction(action)
            if defaultToolButton:
                self.menuButton.setDefaultAction(action)
        self.actions.append(action)

        return action
        
            
    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        
        # Add ToolButton (with Menu)
        self.menuButton = QToolButton()#QPushButton()#QToolButton
        self.menuButton.setMenu(QMenu())
        self.menuButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_path = ':/plugins/c3d/icons/00c3d.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'C3D'),
            callback=self.prepara,
            add_to_toolbar=False,
            add_to_ToolButton=True,
            parent=self.iface.mainWindow())        

        icon_path = ':/plugins/c3d/icons/01xml_import.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Import XML'),
            callback=XML_import,
            add_to_toolbar=False,
            add_to_ToolButton=True,
            defaultToolButton=True,            
            parent=self.iface.mainWindow())

        icon_path = ':/plugins/c3d/icons/02xml_export.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Export XML'),
            callback=XML_export,
            add_to_toolbar=False,
            add_to_ToolButton=True,            
            parent=self.iface.mainWindow())        
       
        #connect to signal to change default action to last clicked
        self.menuButton.triggered.connect(self.menuButton_triggered)
        
        #self.menuButtonAction = self.toolbar.addWidget(self.menuButton)
        self.menuButtonAction = self.iface.addToolBarWidget(self.menuButton)
        
        # will be set False in run()
        self.first_start = True
    
    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&C3D'),
                action)
            self.iface.removeToolBarIcon(action)
            self.iface.removeToolBarIcon(self.menuButtonAction)
            
    def menuButton_triggered(self, action):
        self.menuButton.setDefaultAction(action)
        
    def selectPV(self, pvsList, Prof, QuantTubos, DChega, DSaida):
        #pvsList contem uma lista com os tipos de pvs e suas condicoes
        #pvsList = [Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo, other descriptive fields]
        #list filter sample:[[x,y] for [x,y] in A if x>=2]
        pvsList= [row[:6] for row in pvsList] #remove all but first 6 columns        
        pvsFilterProf = [[Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] for [Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] in pvsList if Prof_Min < Prof <= Prof_Max]
        if pvsFilterProf:
            pvsFilterProf_QuantTubos = [[Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] for [Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] in pvsFilterProf if QuantTubos <= Quant_Max]
            if pvsFilterProf_QuantTubos:
                pvsFilterFinal = [[Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] for [Prof_Min, Prof_Max, Quant_Max, Diam_Chega, Diam_Saida, Tipo] in pvsFilterProf_QuantTubos if (DChega <= Diam_Chega and DSaida<=Diam_Saida)]
                if len(pvsFilterFinal)>=1:
                    resp = pvsFilterFinal[0][5]
                else:
                    resp = u' não cadastrado'
            else:
                resp = u'PV com quantidade de tubos não cadastrada'
        else:
            resp = u'PV com Profundidade não cadastrada'
        return resp
        
    def csvFile2List(self, csvfile):
        #Read csv file, convert to python list, ignore first line (header)
        import csv        
        with open(csvfile, newline='', encoding='ANSI') as f:
            reader = csv.reader(f) #quoting=csv.QUOTE_NONNUMERIC option to consider all numeric
            data = []
            i=0
            for linha in reader:
                if i==0: #ignore first line because of headers
                    i+=1
                else:
                    lineFixed=[]
                    for col in range(0,5):
                        lineFixed.append(float(linha[col]))
                    for col in range(5,len(linha)):
                        lineFixed.append(linha[col].strip())
                    data.append(lineFixed)
            #data = list(reader)
        return data
    
    def Calc_PVs(self, vPipe, vNode): # A profundidade do PV é igual ao PRFM do tubo que sai
        vNode.startEditing()
        
        #Verifica se o node file tem os campos Sump, PROF, TIPO  e cria se necessario
        c3D_fields=[QgsField('Sump',QVariant.Double,'Real',10,3),
                    QgsField('PROF',QVariant.Double,'Real',10,3),
                    QgsField('TIPO',QVariant.String,'String',10,0)]
                    #QgsField('TUBOS',QVariant.Int,'integer',5,0),
                    #QgsField('DIAMCHEG',QVariant.Double,'Real',10,1),
                    #QgsField('DIAMSAI',QVariant.Double,'Real',10,1)]
                    
        self.CheckFields(vNode, c3D_fields) #verifica os campos
        
        #Pega a lista dos PV's de onde partem tubulações para não classificar o PV exutorio
        idx = vPipe.fields().indexOf('PVM')
        pvmLst = vPipe.uniqueValues(idx)       
        
        #Preenche o campo 'Sump' com zero, 
        #'PROF' com valor 'PRFM' do pipe cujo PVM é igual ao PV
        # e 'TIPO' com a funcao criada para selecionar
        for pv in vNode.getFeatures():
            dcid = pv['DC_ID']
            
            expression = 'PVM=\'{}\''.format(dcid)            
            request = QgsFeatureRequest().setFilterExpression(expression)
            matchesSaindo = diamSaindo =  prof = 0
            for pipe in vPipe.getFeatures(request):
                diamSaindo = max(pipe['DIAMETER'],diamSaindo)
                prof = pipe['PRFM']
                matchesSaindo += 1
            
            expression = 'PVJ=\'{}\''.format(dcid)            
            request = QgsFeatureRequest().setFilterExpression(expression)
            matchesCheg = diamCheg = 0
            for pipe in vPipe.getFeatures(request):
                diamCheg = max(pipe['DIAMETER'],diamCheg)
                matchesCheg += 1
            
            QuantTubos = matchesCheg+matchesSaindo
            pv['Sump']= 0
            pv['PROF']= prof
            
            #verifica se não é um PV exutorio
            if dcid in pvmLst:
                calcTipo = self.selectPV(self.PVsTipos, prof, QuantTubos, diamCheg, diamSaindo)
                pv['TIPO']= 'PV TIPO {}'.format(calcTipo)
            else:            
                pv['TIPO']= 'PV Final'
            #fields for checking
            #pv['TUBOS']= QuantTubos
            #pv['DIAMCHEG']= diamCheg
            #pv['DIAMSAI']= diamSaindo
            vNode.updateFeature(pv)
            valor=self.progress.value()+1
            self.progress.setValue(valor)
            QApplication.processEvents()
        return
    
    def CheckFields(self, vLayer, chkFields):
        for fld in chkFields:
            FldName = fld.name()
            field_index = vLayer.fields().indexFromName(FldName)
            if field_index == -1:            
                vLayer.addAttribute(fld)
        vLayer.updateFields()
    
    def Calc_Pipes(self, vPipes):
        vPipes.startEditing()
        
        #Verifica se tem o campo Descript e cria se necessario
        c3D_fields=[QgsField('Descript',QVariant.String,'String',100,0)]                    
        self.CheckFields(vPipes, c3D_fields) #verifica os campos
        
        for pipe in vPipes.getFeatures():
                diam = int(pipe['DIAMETER'])
                if diam<=400:
                    tuboTipo ='PVC RIGIDO PB JE DN {}'
                else:
                    tuboTipo = 'CONCRETO PB DN {}'
                pipe['Descript'] = tuboTipo.format(diam)
                vPipes.updateFeature(pipe)
                valor=self.progress.value()+1
                self.progress.setValue(valor)
                QApplication.processEvents()
    
    def prepara(self):
        """Run method that performs all the real work"""
        pipesLyr = self.Common.PegaQEsgLayer('PIPES')
        if not pipesLyr:
            return

        nodesLyr = self.Common.PegaQEsgLayer('JUNCTIONS')      
        if not nodesLyr:
            return
        
        #Start progressBar
        self.progress, self.progressMessageBar, self.cancelButton = self.Common.startProgressBar('Iniciando...')
        try:
            totRecs = pipesLyr.featureCount() + nodesLyr.featureCount()
            self.progress.setMaximum(totRecs)
            
            csvfile = os.path.join(self.plugin_dir,'dados','pvs_tipo.csv')
            self.PVsTipos = self.csvFile2List(csvfile)
            self.progressMessageBar.setText('Calculando PVs')
            self.Calc_PVs(pipesLyr, nodesLyr)
            self.progressMessageBar.setText('Calculando Tubos')
            self.Calc_Pipes(pipesLyr)

        except Exception as e:
            gotErr = [u'Erro na execução: {}'.format(type(e).__name__), Qgis.Warning]
            QgsMessageLog.logMessage(traceback.format_exc(), 'C3D', Qgis.Critical)
        else:
            gotErr = ['Concluido com sucesso!', Qgis.Info]
        finally:
            self.iface.messageBar().popWidget(self.progressMessageBar)
            self.iface.messageBar().pushMessage("C3D", gotErr[0], level=gotErr[1], duration=10)
            #iface.messageBar().clearWidgets()
            iface.messageBar().findChildren(QToolButton)[0].setHidden(False)
        
        '''
        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start == True:
            self.first_start = False
            self.dlg = c3dDialog()

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass
        '''