# -*- 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.core import *
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import QAction, QApplication, QProgressBar, QFileDialog, QTreeWidgetItem
from qgis.utils import *
from ...QEsg_01Campos import *

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

import traceback, inspect
import xml.etree.ElementTree as ET

dlg = c3dDialog()
tw = dlg.treeWidget
ns = '{http://www.landxml.org/schema/LandXML-1.2}'
nsLen = len(ns)
msgBar = QgsMessageBar() 
dlg.layout().addWidget(msgBar)
dlg.mQgsFileWidget.setFilter("XML file (*.xml *.XML);;All Files (*.*)")
c3d_elemTypes= {'Surfaces': ['P','F'], #['Pnts','Faces']
                'Alignments':['Line'],
                'PipeNetworks':['Struct','Pipe']}   

def writeMsg(msg,lvl=Qgis.Info):
    msgBar.pushMessage("C3D", msg, level=lvl, duration=5)

def CarregaEstilo(vLayer, Estilo):
    basepath = os.path.dirname(__file__)
    FullPath=os.path.join(basepath, 'styles/'+Estilo)
    vLayer.loadNamedStyle(FullPath)

def PegaQEsgLayer(aForma):
    proj = QgsProject.instance()
    #aForma='PIPES'
    ProjVar=proj.readEntry("QEsg", aForma)[0]
    if ProjVar=='':
        #msgTxt=QCoreApplication.translate('QEsg','Layer Indefinido: ') +aForma
        #iface.messageBar().pushMessage("QEsg:", msgTxt, level=Qgis.Warning, duration=10)
        return False
    LayerLst=proj.mapLayersByName(ProjVar)
    if LayerLst:
        layer = proj.mapLayersByName(ProjVar)[0]
        return layer
    else:
        #msgTxt=aForma+'='+ProjVar+QCoreApplication.translate('QEsg',u' (Layer não encontrado)')
        #iface.messageBar().pushMessage("QEsg:", msgTxt, level=Qgis.Warning, duration=10)
        return False


def twItemChoosed(item, column):
    if item:
        pai = item.parent()
        if pai:
            elemType = pai.data(0,Qt.DisplayRole)
            XMLnode=item.data(0,Qt.UserRole)
            print('pai:',elemType)
            print(item, item.data(0,Qt.DisplayRole), column, XMLnode)
            if elemType=='Surfaces':
                XML_import_Mesh(XMLnode)
            elif elemType=='PipeNetworks':
                XML_import_PipeNetwork(XMLnode)
            else:
                writeMsg('{} Element type not implemented yet!'.format(elemType),Qgis.Warning)
        else:
            writeMsg('Can not select top level item!',Qgis.Warning)
        '''
        for ix in tw.selectedIndexes():

            if ix.data().childCount()>0:
                print('childCount>0')
            else:
                print('childCount<=0')

            text = ix.data(Qt.DisplayRole) # or ix.data()
            print(text)
        '''
    else:
        iface.messageBar().pushMessage("C3D", 'Cancelled! Nothing selected!', level=Qgis.Info, duration=3)
def XML_import():
    dlg.show()        
    result = dlg.exec_() # Run the dialog event loop
    
    # See if OK was pressed
    if result:
        tw.itemDoubleClicked.emit(tw.currentItem(),tw.currentColumn())
        
def reloadTreeWidget(xmlPath):
    #xmlPath=r'C:\Users\jorgealmerio\Documents\Hydros\Projetos\P0398_Camacari\00_Outros\TestesMalha\LandXML\Alinhamentos_XML.xml'    
    #xmlPath, __ = QFileDialog.getOpenFileName(caption=tr(u'Importar XML:'),
    #                                         filter="XML file (*.xml *.XML);;All Files (*.*)")
    try:
        if os.path.isfile(xmlPath):     
            tw.clear()                
            QApplication.setOverrideCursor(Qt.WaitCursor)
            tree = ET.parse(xmlPath)
            root = tree.getroot()                
            for tipo in root:#[4:]:
                tag = tipo.tag[nsLen:]
                print(tag)
                if tag in c3d_elemTypes:
                    twItem = QTreeWidgetItem([tag])            
                    tw.addTopLevelItem(twItem)
                    pai = tw.topLevelItem(tw.topLevelItemCount()-1)                    
                    for elem in tipo:
                        try:
                            nome = elem.attrib['name']
                        except:
                            nome ='no name'
                        nroFilhos = pai.childCount()                
                        QTreeWidgetItem(pai)
                        twItem = pai.child(nroFilhos)
                        nodeName = c3d_elemTypes[tag][0]
                        nroSubItens = '{}'.format(countNodes(elem,nodeName)) #str(len(list(elem)))
                        twItem.setData(0,Qt.UserRole,elem)
                        twItem.setText(0,nome)
                        twItem.setText(1,nroSubItens)
                        print(' |-->'+nome)

                tw.expandAll()
                tw.resizeColumnToContents(0) #resize first Column
                tw.header().resizeSection(0, int(tw.columnWidth(0)*1.2)) #increase first column size in 20%
    finally:
        QApplication.restoreOverrideCursor()
        
def btnRefresh_clicked():
    reloadTreeWidget(dlg.mQgsFileWidget.filePath())

#connect to treeWidget signals
dlg.mQgsFileWidget.fileChanged.connect(reloadTreeWidget)
dlg.btnRefresh.clicked.connect(btnRefresh_clicked)
tw.itemDoubleClicked.connect(twItemChoosed)



def countNodes(rootNode, subNode):
    i=0
    for child in rootNode.findall(".//{0}{1}".format(ns,subNode)):
        i+=1
    return i

def removeDesc(texto):
    #remove string (description) from just before last open parenthesis '(' to end if exists
    pos=texto.rfind('(')
    if pos!=-1: #if find last open parenthesis '('
        return texto[:pos-1]
    else:
        return texto

def XML_import_PipeNetwork(rootNode):
    proj = QgsProject.instance()
    nome = os.path.basename(dlg.mQgsFileWidget.filePath())        
    CamposClasse=QEsg_01Campos()
    
    curSrc = iface.mapCanvas().mapSettings().destinationCrs().authid()    
    NomeRede = rootNode.get('name')
    
    junctLyr = PegaQEsgLayer('JUNCTIONS')
    UpdJunct=False #Update Mode
    if junctLyr:
        resp=QMessageBox.question(None,'QEsg',QCoreApplication.translate('QEsg','Deseja atualizar o layer "{}"?'.format(junctLyr.name())),
                                          QMessageBox.Yes, QMessageBox.No)
        if resp==QMessageBox.Yes:
            UpdJunct=True

    pipesInver = {} #{refPipe: elev}
    ptos={} #{name: [[x,y],pipesInver} 
    
    #Update or create new
    if UpdJunct:
        ptoLayer = junctLyr
    else:
        tipoStr = "Point?crs="+curSrc       
        ptoLayer = QgsVectorLayer(tipoStr, 'Struct '+NomeRede, "memory")
        #Cria os campos padroes sem perguntar    
        CamposClasse.CriaCampos('JUNCTIONS',ptoLayer, SilentRun=True)
        #Cria campos c3d complementares
        ptoFlds = [QgsField("TIPO", QVariant.String)] #[QgsField("name", QVariant.String),QgsField("desc", QVariant.String),QgsField("elevRim", QVariant.Double)]
        ptoLayer.dataProvider().addAttributes(ptoFlds)    
        ptoLayer.updateFields()
    
    lineLyr = PegaQEsgLayer('PIPES')
    UpdPipe=False #Update Mode
    if lineLyr:
        resp=QMessageBox.question(None,'QEsg',QCoreApplication.translate('QEsg','Deseja atualizar o layer "{}"?'.format(lineLyr.name())),
                                          QMessageBox.Yes, QMessageBox.No)
        if resp==QMessageBox.Yes:
            UpdPipe=True
    
    #Update or create new
    if UpdPipe:
        lineLayer = lineLyr
    else:    
        tipoStr = "LineString?crs="+curSrc
        lineLayer = QgsVectorLayer(tipoStr, 'Pipe '+NomeRede, "memory")
        #Cria os campos padroes sem perguntar    
        CamposClasse.CriaCampos('PIPES',lineLayer, SilentRun=True)
        lineLayer.updateFields()
        #Cria campos c3d complementares
        lineFlds = [QgsField("Descript", QVariant.String)]
        lineLayer.dataProvider().addAttributes(lineFlds)
        lineLayer.updateFields()

    if ptoLayer:
        try:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            i=0
            if UpdJunct:
                ptoLayer.startEditing()
            #loop for structs
            notFoundNodes=[]
            notFoundPipes=[]
            dupFoundNodes=[]
            dupFoundPipes=[]
            for child in rootNode.findall(".//{0}{1}".format(ns,c3d_elemTypes['PipeNetworks'][0])): #network structs
                i+=1
                name = removeDesc(child.get('name'))
                desc = child.get('desc')
                elevRim = float(child.get('elevRim')) or 0
                y,x = list(map(float,child.find(ns+'Center').text.split()))
                if UpdJunct:
                    request = QgsFeatureRequest().setFilterExpression( '"DC_ID" = \'{}\''.format(name) )
                    it = ptoLayer.getFeatures( request )
                    LstIT = list(it)
                    itCount=len(LstIT)
                    if itCount==0:
                        notFoundNodes.append(name)
                        feat = QgsFeature(ptoLayer.fields())
                        ptoLayer.dataProvider().addFeature(feat) #hoje
                    elif itCount>1:
                        listOfIds=[]
                        for i in range(itCount-2):
                            feat = LstIT[i]
                            listOfIds.append(feat.id())
                        ptoLayer.deleteFeatures( listOfIds )
                        dupFoundNodes.append(name)
                        feat = LstIT[0]                      
                    else:
                        feat = LstIT[0] #get the first and unique feature
                else:
                    feat = QgsFeature(ptoLayer.fields())
                feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x,y)))
                #feat.setAttributes([name, desc, elevRim])
                feat['DC_ID'] = name
                feat['TIPO'] = desc
                feat['COTA_TN'] = elevRim
                
                if UpdJunct:
                    ptoLayer.updateFeature(feat)
                else:
                    ptoLayer.dataProvider().addFeature(feat)
                
                
                #loop for get pipes invert elevation from structs
                pipesInver = {}
                for subchild in child.findall(ns+'Invert'):
                    refPipe=removeDesc(subchild.get('refPipe'))
                    elev=subchild.get('elev')
                    pipesInver[refPipe]=elev
                
                ptos[name]=[[x,y],pipesInver]
            
            ptoLayer.updateExtents() #hoje
            
            #loop for pipes
            for child in rootNode.findall(".//{0}{1}".format(ns,c3d_elemTypes['PipeNetworks'][1])): #network pipes
                i+=1
                if UpdPipe:
                    lineLayer.startEditing()
                #for subchild in child.findall(".//*"):
                #    print('subchild=',subchild)#.find('Center'))
                name = removeDesc(child.get('name'))
                desc = child.get('desc')
                refStart = removeDesc(child.get('refStart'))
                refEnd = removeDesc(child.get('refEnd'))
                slope = float(child.get('slope')) or 0
                diameter = float(child.find(ns+'CircPipe').get('diameter')) or 0
                upElev = ptos[refStart][1][name]                
                downElev = ptos[refEnd][1][name]                
                pto1 = QgsPointXY(ptos[refStart][0][0],ptos[refStart][0][1])
                pto2 = QgsPointXY(ptos[refEnd][0][0],ptos[refEnd][0][1])
                
                if UpdPipe:                
                    request = QgsFeatureRequest().setFilterExpression( '"DC_ID" = \'{}\''.format(name) )
                    it = lineLayer.getFeatures( request )
                    LstIT = list(it)
                    itCount=len(LstIT)
                    if itCount==0:
                        notFoundPipes.append(name)
                        feat = QgsFeature(lineLayer.fields())
                        lineLayer.dataProvider().addFeature(feat) #hoje
                    elif itCount>1:
                        listOfIds=[]
                        for i in range(itCount-2):
                            feat = LstIT[i]
                            listOfIds.append(feat.id())
                        lineLayer.deleteFeatures( listOfIds )
                        dupFoundPipes.append(name)
                        feat = LstIT[0]                      
                    else:
                        feat = LstIT[0] #get the first and unique feature                
                else:
                    feat = QgsFeature(lineLayer.fields())
                    
                feat.setGeometry(QgsGeometry.fromPolylineXY([pto1,pto2]))
                #feat.setAttributes([name, desc, slope, diameter, upElev, downElev])
                feat['DC_ID']=name
                feat['Descript']=desc
                feat['DECL']=slope
                feat['DIAMETER']=diameter
                feat['CCM']=upElev
                feat['CCJ']=downElev
                feat['PVM']=refStart
                feat['PVJ']=refEnd
                
                colTre = re.findall(r"\d+", name)
                feat['Coletor']=int(colTre[0]) if len(colTre)>=1 else 0                
                feat['Trecho']=int(colTre[1]) if len(colTre)>=2 else 0
                
                if UpdPipe:
                    lineLayer.updateFeature(feat)
                else:
                    lineLayer.dataProvider().addFeature(feat) 
                        
            lineLayer.updateExtents()
            if not UpdPipe:
                CarregaEstilo(lineLayer,'c3d_pipe.qml')
                proj.addMapLayer(lineLayer)
            
            ptoLayer.updateExtents()
            if not UpdJunct:
                CarregaEstilo(ptoLayer,'c3d_struct.qml')
                proj.addMapLayer(ptoLayer)
            
            iface.setActiveLayer(ptoLayer)
            iface.zoomToActiveLayer()            
            if UpdJunct or UpdPipe:
                msg='Network updated: {}'.format(NomeRede)
                if len(notFoundNodes)>0 or len(dupFoundNodes)>0 or len(notFoundPipes) or len(dupFoundPipes)>0:
                    QgsMessageLog.logMessage('notFoundNodes:{}'.format(notFoundNodes),'C3D',level=Qgis.Warning)
                    QgsMessageLog.logMessage('dupFoundNodes:{}'.format(dupFoundNodes),'C3D',level=Qgis.Warning)
                    QgsMessageLog.logMessage('notFoundPipes:{}'.format(notFoundPipes),'C3D',level=Qgis.Warning)
                    QgsMessageLog.logMessage('dupFoundPipes:{}'.format(dupFoundPipes),'C3D',level=Qgis.Warning)
                    msg+=' Check log for errors'
                iface.messageBar().pushMessage("C3D: ", msg, level=Qgis.Info, duration=5)
            else:
                iface.messageBar().pushMessage("C3D: ", 'Network imported: {}'.format(NomeRede), level=Qgis.Info, duration=5)

            dlg.close()
        finally:
            QApplication.restoreOverrideCursor()
    else:
        iface.messageBar().pushMessage("C3D",'Cancelled!', Qgis.Info)

def XML_import_Mesh(rootNode):
    #funcName = inspect.stack()[0][3]
    #iface.messageBar().pushMessage("C3D", inspect.stack()[0][3], level=Qgis.Info, duration=10)
    proj = QgsProject.instance()
    
    #prjfi= proj.readPath("./") #get project folder
    nome = os.path.basename(dlg.mQgsFileWidget.filePath())    
    outPath, __ = QFileDialog.getSaveFileName(caption=tr(u'Local para salvar o arquivo \'{}\' como uma malha (*.2dm):').format(nome), 
                                             filter="Arquivo de malha (*.2dm *.2DM)")      
    if outPath:
        try:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            with open(outPath,"w") as outFile:            
                #{http://www.landxml.org/schema/LandXML-1.2}Surfaces
                outFile.write('MESH2D\n') #Header
                i=0
                #loop for triangule faces
                for child in rootNode.findall(".//{}F".format(ns)): #surface faces
                    i+=1
                    #id = child.get('n')
                    vertIds = child.text.split()
                    linha = 'E3T    {}    {}    {}    {}    1'.format(i, vertIds[0],vertIds[1],vertIds[2])
                    #linha = 'tag={}, text={}, attrib={}'.format(child.tag, child.text, child.attrib)
                    outFile.write(linha+'\n')
                    #print(linha)
                
                #loop for triangule vertices
                for child in rootNode.findall(".//{}P".format(ns)): #surface vertices
                    id = child.get('id')
                    vertIds = child.text.split()
                    linha = 'ND    {}    {}    {}    {}'.format(id, vertIds[1],vertIds[0],vertIds[2])
                    #linha = 'tag={}, text={}, attrib={}'.format(child.tag, child.text, child.attrib)
                    outFile.write(linha+'\n')
                    #print(linha) 
                
                nome_camada=os.path.splitext(os.path.basename(outPath))[0]
                mapCRS = iface.mapCanvas().mapSettings().destinationCrs()
                layer = QgsMeshLayer(outPath,nome_camada,'mdal')
                layer.setCrs(mapCRS)                
                proj.addMapLayer(layer)
                iface.setActiveLayer(layer)
                iface.zoomToActiveLayer()
                layer.createMapRenderer(QgsRenderContext()) #create render to update mesh visualization
                QApplication.processEvents()
                iface.mapCanvas().refreshAllLayers()
                QApplication.processEvents()
                iface.messageBar().pushMessage("C3D", 'Mesh Created on: {}'.format(outPath), level=Qgis.Info, duration=5)
                dlg.close()
        finally:
            QApplication.restoreOverrideCursor()
    else:
        iface.messageBar().pushMessage("C3D",'Cancelled!', Qgis.Info)

#def XML_export(): #moved to c3d_xml_export.py
#    iface.messageBar().pushMessage("C3D: ", inspect.stack()[0][3]+' ! Not implemented yet ! ', level=Qgis.Info, duration=10)

def tr(string):
    return QCoreApplication.translate('C3D', string)
