"""
/***************************************************************************
                                 A QGIS plugin
 Набор инструментов для работы с материалами документации территориального планирования
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2024-03-18
        git sha              : $Format:%H$
        copyright            : (C) 2024 by I.Bukharin/Mirproekt
        email                : iabukharin@gmail.com
 ***************************************************************************/
 Функции экспорта в GML
"""

from qgis.PyQt.QtCore import QVariant
from qgis.core import QgsGeometry, QgsProject, QgsCoordinateTransform

def createGMLgeometryString(geomForGML, featCRS, targetCRS):
    tr = QgsCoordinateTransform(featCRS, targetCRS, QgsProject.instance())
    geomForGML.transform(tr)
    if geomForGML.isEmpty():
        return ''
    if targetCRS.mapUnits() ==  0:
        precisVal = 4
    else:
        precisVal = 10
    gmlString = '<ogr:geometryProperty>\n'
    geomType = str(geomForGML.wkbType()).replace('WkbType.','')
    # GML types Point, Curve (LineString), Surface (Polygon), Geometry, MultiPoint, MultiCurve, MultiSurface, MultiGeometry
    geomForGML.removeDuplicateNodes()
    if geomType == 'MultiPolygon' or geomType == '6':
        gmlString += '<gml:MultiSurface>\n'
        for polygon in geomForGML.constParts():
            if polygon.isEmpty():
                continue
            gmlString += '<gml:surfaceMember>\n'
            gmlString += '<gml:Polygon>\n'
            pointsList = [v for v in polygon.vertices()]
            point0Flag = True
            exteriorFlag = True
            for point in pointsList:
                if point0Flag:
                    point0Flag = False
                    coordList = []
                    point0 = point
                    if exteriorFlag:
                        gmlString += '<gml:exterior>\n<gml:LinearRing>\n<gml:posList>'
                    else:
                        gmlString += '<gml:interior>\n<gml:LinearRing>\n<gml:posList>'
                    coordList.append(str(round(point.x(), precisVal)))
                    coordList.append(str(round(point.y(), precisVal)))
                    continue
                if point0 == point:
                    coordList.append(str(round(point.x(), precisVal)))
                    coordList.append(str(round(point.y(), precisVal)))
                    gmlString += ' '.join(coordList)
                    coordList = []
                    point0Flag = True
                    if exteriorFlag:
                        gmlEnd = '</gml:posList>\n</gml:LinearRing>\n</gml:exterior>\n'
                        gmlString += gmlEnd
                        exteriorFlag = False
                    else:
                        gmlEnd = '</gml:posList>\n</gml:LinearRing>\n</gml:interior>\n'
                        gmlString += gmlEnd
                coordList.append(str(round(point.x(), precisVal)))
                coordList.append(str(round(point.y(), precisVal)))
            gmlString += '</gml:Polygon>\n'
            gmlString += '</gml:surfaceMember>\n'
        gmlString += '</gml:MultiSurface>\n'
    elif geomType == 'MultiLineString' or geomType == '5':
        gmlString += '<gml:MultiCurve>\n'
        for line in geomForGML.constParts():
            if line.isEmpty():
                continue
            gmlString += '<gml:curveMember>\n<gml:LineString>\n<gml:posList>'
            posList = []
            for point in line.vertices():
                posList.append(str(round(point.x(), precisVal)))
                posList.append(str(round(point.y(), precisVal)))
            gmlString += ' '.join(posList)
            gmlString += '</gml:posList>\n</gml:LineString>\n</gml:curveMember>\n'
        gmlString += '</gml:MultiCurve>\n'
    elif geomType == 'MultiPoint' or geomType == '4':
        gmlString += '<gml:MultiPoint>\n'
        for point in geomForGML.constParts():
            if point.isEmpty():
                continue
            gmlString += '<gml:pointMember>\n<gml:Point>\n<gml:pos>'
            gmlString += ' '.join([str(round(point.x(), precisVal)), str(round(point.y(), precisVal))])
            gmlString += '</gml:pos>\n</gml:Point>\n</gml:pointMember>\n'
        gmlString += '</gml:MultiPoint>\n'
    elif geomType == 'Point' or geomType == '1':
        gmlString += '<gml:Point>\n<gml:pos>'
        point = geomForGML.asPoint()
        gmlString += ' '.join([str(round(point.x(), precisVal)), str(round(point.y(), precisVal))])
        gmlString += '</gml:pos>\n</gml:Point>\n'
    elif geomType == 'LineString' or geomType == '2':
        gmlString += '<gml:LineString>\n<gml:posList>'
        posList = []
        # print(geomForGML.asPolyline())
        for point in geomForGML.vertices():
            posList.append(str(round(point.x(), precisVal)))
            posList.append(str(round(point.y(), precisVal)))
        gmlString += ' '.join(posList)
        gmlString += '</gml:posList>\n</gml:LineString>\n'
    elif geomType == 'Polygon' or geomType == '3':
        gmlString += '<gml:Polygon>\n'
        pointsList = [v for v in geomForGML.vertices()]
        point0Flag = True
        exteriorFlag = True
        # print(pointsList)
        for point in pointsList:
            if point0Flag:
                point0Flag = False
                coordList = []
                point0 = point
                if exteriorFlag:
                    gmlString += '<gml:exterior>\n<gml:LinearRing>\n<gml:posList>'
                else:
                    gmlString += '<gml:interior>\n<gml:LinearRing>\n<gml:posList>'
                coordList.append(str(round(point.x(), precisVal)))
                coordList.append(str(round(point.y(), precisVal)))
                continue
            if point0 == point:
                coordList.append(str(round(point.x(), precisVal)))
                coordList.append(str(round(point.y(), precisVal)))
                gmlString += ' '.join(coordList)
                coordList = []
                point0Flag = True
                if exteriorFlag:
                    gmlEnd = '</gml:posList>\n</gml:LinearRing>\n</gml:exterior>\n'
                    gmlString += gmlEnd
                    exteriorFlag = False
                else:
                    gmlEnd = '</gml:posList>\n</gml:LinearRing>\n</gml:interior>\n'
                    gmlString += gmlEnd
            coordList.append(str(round(point.x(), precisVal)))
            coordList.append(str(round(point.y(), precisVal)))
        gmlString += '</gml:Polygon>\n'
    else:
        return ''
    gmlString += '</ogr:geometryProperty>\n'
    return gmlString

def checkAttrValueForNull(valueForCheck, field):
    """
    Проверяет на отсутствие значения атрибута

    Args:
        valueForCheck (any): значение атрибута
        field (QgsField): атрибут
    
    Returns:
        bool: True если значение атрибутна отсутсвует
    """

    nullFlag = False
    featureFieldType = field.type()
    if valueForCheck is None:
        nullFlag = True
    elif QVariant(valueForCheck).isNull():
        nullFlag = True
    elif str(valueForCheck) in ['NULL', 'Null']:
        nullFlag = True
    elif featureFieldType == QVariant.String:
        if valueForCheck == '' or valueForCheck in ['NULL', 'Null', ' ', 'None', 'null']:
            nullFlag = True
    else:
        if valueForCheck == 0:
            nullFlag = True
        if valueForCheck == 0.0:
            nullFlag = True
    return nullFlag

def checkAttrValueForNull2(valueForCheck, field):
    """
    Проверяет на отсутствие значения атрибута

    Args:
        valueForCheck (any): значение атрибута
        field (QgsField): атрибут
    
    Returns:
        bool: True если значение атрибутна отсутсвует
    """

    nullFlag = False
    featureFieldType = field.type()
    if valueForCheck is None:
        nullFlag = True
    elif QVariant(valueForCheck).isNull():
        nullFlag = True
    elif str(valueForCheck) in ['NULL', 'Null']:
        nullFlag = True
    elif featureFieldType == QVariant.String:
        if valueForCheck == '' or valueForCheck in ['NULL', 'Null', ' ', 'None', 'null']:
            nullFlag = True
    else:
        if valueForCheck == 0:
            nullFlag = True
        if valueForCheck == 0.0:
            nullFlag = True
    return nullFlag

def createGMLstring (featForGML, complexTypeName, complexType, featCRS, targetCRS, onlyReqAttrFlag=True):
    gmlString = '<gml:featureMember>\n'
    valueGLOBALID = featForGML['GLOBALID']
    gmlString += f'<ogr:{complexTypeName.replace("_Type", "")} gml:id="{valueGLOBALID}">\n'
    
    geometryGmlString = createGMLgeometryString(QgsGeometry(featForGML.geometry()), featCRS, targetCRS)
    if geometryGmlString == '':
        return ''
    gmlString += geometryGmlString

    for field in featForGML.fields():
        fieldName = field.name()
        if fieldName not in complexType['attributes'].keys():
            continue
        if onlyReqAttrFlag and complexType['attributes'][fieldName]["minOccurs"] == 'N':
            continue
        mirDepend = complexType['attributes'][fieldName].get('mirDepend', '')
        if mirDepend != '':
            mirDependField = mirDepend[:mirDepend.find('=')]
            mirDependValueList = [int(x) for x in mirDepend[mirDepend.find('=')+2:-1].split(',')]
            if featForGML[mirDependField] in mirDependValueList:
                if checkAttrValueForNull(featForGML[fieldName], field):
                    gmlString += f'<ogr:{fieldName}>0</ogr:{fieldName}>\n'
                else:
                    gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n'
            else:
                #<ogr:COMPL_NAME xsi:nil="true"/>
                #gmlString += f'<ogr:{fieldName} xsi:nil="true"/>\n'
                gmlString += f'<ogr:{fieldName}>0</ogr:{fieldName}>\n'
        else:
            if checkAttrValueForNull(featForGML[fieldName], field):
                gmlString += f'<ogr:{fieldName}>0</ogr:{fieldName}>\n'
            else:
                gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n'
        """ if complexType['attributes'][fieldName]["minOccurs"] == 'C':
            if checkAttrValueForNull(featForGML[fieldName], field):
                gmlString += f'<ogr:{fieldName}>0</ogr:{fieldName}>\n'
            else:
                gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n'
        else:
            gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n' """

        """ if mirDepend == '':
            gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n'
        else:
            depAttrName, depAttrVals = mirDepend.split('=')[0], mirDepend.split('=')[1].translate({91: None, 93:None}).replace(' ', '').split(',')
            if str(featForGML[depAttrName]) in depAttrVals:
                gmlString += f'<ogr:{fieldName}>{featForGML[fieldName]}</ogr:{fieldName}>\n' """

    gmlString += f'</ogr:{complexTypeName.replace("_Type", "")}>\n'
    gmlString += f'</gml:featureMember>\n'
    return gmlString