"""Modul pomocniczy dla geometrii gml
"""
# try:
#     import gdal
# except:
#     import osgeo.gdal as gdal 
import processing
from osgeo import ogr, osr
from qgis.core import QgsVectorLayer, QgsProject, QgsFeature, QgsOgcUtils, QgsVectorLayerUtils 
from Mapa_PU.swdl.model.tags import TagsLayer
from Mapa_PU.swdl.model.swdl.geom import GeomInterface, Geom
from Mapa_PU.swdl.model.swdl.basic_object_geom import BasicObjectGeom
from Mapa_PU.swdl.model.swdl.line_geom import LineGeom

"""Klasa pomocnicza dla geometrii
"""
class GeometryHelper():
    
    def __init__(self):
        self.driver = ogr.GetDriverByName('ESRI Shapefile')
        
#     def set_geometry(self,path_to_shapefile,gml_geometry,parameters):
#         """Wstawia geometrię do pliku shp
#         :param path_to_shapefile; scierzka do pliku
#         :param gml_geometry; geometria w formacie gml
#         :param parameters; parametry w formie tupli tupli ((a,b),(c,d))
#         """
#         try:
#             const=['xmlns:gml="http://www.opengis.net/gml"',
#                    'xmlns="https://www.bdl.lasy.gov.pl/portal/swdl"',
#                    'xmlns:xlink="http://www.w3.org/1999/xlink"',
#                    'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:docbook="http://docbook.org/ns/docbook"']
#             #dekodowanie z binary na string
#             gml_geometry=gml_geometry.decode("utf-8")
#             #TODO do przebudowy wyciągnac z drzewa xml string
#             #usuniecie przestrzeni xml z geometrii
#             for con in const:
#                 gml_geometry=gml_geometry.replace(con,'')
#             #Przywrócenie do wersji starszej gml
#             gml_geometry=gml_geometry.replace('MultiSurface','MultiPolygon').replace('surfaceMember','polygonMember')
#             
#             dataset = self.driver.Open(path_to_shapefile,1)
#             layer = dataset.GetLayer()
#             geometry=ogr.CreateGeometryFromGML(gml_geometry)
#             feature = ogr.Feature(layer.GetLayerDefn())
#             for param in parameters:
#                 feature.SetField(param[0],param[1])
#             feature.SetGeometry(geometry)
#             layer.CreateFeature(feature)
#             dataset.Destroy()
#             
#         except Exception as e:
#             raise e
        
    def set_feature(self,name:str,gml_geometry,parameters:()): 
        """Wstawia obiekt do warstwy
        :param name: Nazwa warstwy
        :param gml_geometry: Geometria w formie gml
        :param parameters: Parametry w formie tupli tupli ((a,b),(c,d))
        """   
        try:
            const=['xmlns:gml="http://www.opengis.net/gml"',
                   'xmlns="https://www.bdl.lasy.gov.pl/portal/swdl"',
                   'xmlns:xlink="http://www.w3.org/1999/xlink"',
                   'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:docbook="http://docbook.org/ns/docbook"']
            #dekodowanie z binary na string
            gml_geometry=gml_geometry.decode("utf-8")
            #usuniecie przestrzeni xml z geometrii
            for con in const:
                gml_geometry=gml_geometry.replace(con,'')
            #Przywrócenie do wersji starszej gml
            gml_geometry=gml_geometry.replace('MultiSurface','MultiPolygon').replace('surfaceMember','polygonMember')
            geometry=QgsOgcUtils.geometryFromGML(gml_geometry)
            layer=self.get_first_layer(name)
            feature=QgsVectorLayerUtils.createFeature(layer,geometry)
            #Ustawienie parametrów
            for param in parameters:
                feature.setAttribute(feature.fieldNameIndex(param[0]),param[1])
            layer.dataProvider().addFeatures([feature])
        except Exception as e:
            raise e
#     def set_geometry_(self,path_to_shapefile,gml_geometry,parameters):
#         """Wstawia geometrię do pliku shp i ustawia parametry
#         :param path_to_shapefile; scierzka do pliku
#         :param gml_geometry; geometria
#         :param parameters; parametry
#         """
#         try:
#             dataset = self.driver.Open(path_to_shapefile)
#             layer = dataset.GetLayer()
#             geometry=ogr.CreateGeometryFromGML(str(gml_geometry))
#             feature = ogr.Feature(layer.GetLayerDefn())
#             feature.SetGeometry(geometry)
#             layer.CreateFeature(feature)
#             feature.Destroy()
#         except Exception as e:
#             raise e
    
    def get_pnenomena_geometries(self,name:str,collect:bool):
        """Zwraca geometrie Phenomena z pliku shp
        :param path_to_shapefile: ścieżka dopliku shp
        :param collect: zezwolenie na zamianę obiektów w multiobiekty
        """      
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.GetLayer()
            if collect:
                layer=self.get_collect_feature(layer,[TagsLayer.ADDRESS.value,TagsLayer.SINGULARITY_CODE.value,TagsLayer.NR_SINGULARITY.value,TagsLayer.SINGULARITY_AREA.value])
            return [('{}_{}'.format(feature[TagsLayer.ADDRESS.value],feature[TagsLayer.NR_SINGULARITY.value]), self.convert_to_gml(feature)) for feature in layer.getFeatures()]
            
        except Exception as e:
            raise e
        
    def get_spec_areas_geometries(self,name:str):
        ##Zwraca geometrie Spec Area z pliku shp      
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.GetLayer()
            layer=self.get_collect_feature(layer,[TagsLayer.ADDRESS.value,
                                                  TagsLayer.CODE_PNSW.value,
                                                  TagsLayer.NR_PNSW.value,
                                                  TagsLayer.PARCEL_NR.value,
                                                  TagsLayer.ADMINISTRATIVE_ADDRESS.value])
            return [('{}_{}'.format(feature[TagsLayer.ADDRESS.value],feature[TagsLayer.NR_PNSW.value]),feature[TagsLayer.PARCEL_NR.value] ,self.convert_to_gml(feature)) for feature in layer.getFeatures()]
            
        except Exception as e:
            raise e
        
    def get_subareas_geometries(self,name:str):
        ##Zwraca geometrie Subarea
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.GetLayer()
            layer=self.get_collect_feature(layer,[TagsLayer.ADDRESS.value,TagsLayer.LINE_RECORD.value])
            #knieczna zmiana zwiazana z schematem (w schemacie jest nowsza wersja gdal niz w qgis)
            #'MultiPolygon' => 'MultiSurface' i 'polygonMember'=>'surfaceMember' dla obiektów typu multipolygon
            return [('{}'.format(feature[TagsLayer.ADDRESS.value]), self.convert_to_gml(feature)) for feature in layer.getFeatures()]
            
        except Exception as e:
            raise e
    
    def get_subarea_parcel_geometries(self,name:str):
        ##Zwraca warstwę działek ewidencyjnych
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.GetLayer()
            layer=self.get_collect_feature(layer, [TagsLayer.ADMINISTRATIVE_ADDRESS.value,TagsLayer.PARCEL_NR.value])
            return [(feature[TagsLayer.ADMINISTRATIVE_ADDRESS.value], feature[TagsLayer.PARCEL_NR.value],self.convert_to_gml(feature)) for feature in layer.getFeatures()]
        except Exception as e:
            raise e
        
    def get_parcel_land_use_geometries(self,name:str):
        """Zwraca geometrię użytków"""
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.GetLayer()
            layer=self.get_collect_feature(layer, [TagsLayer.ADMINISTRATIVE_ADDRESS.value,
                                                   TagsLayer.PARCEL_NR.value,
                                                   TagsLayer.AREA_USE_DIC_CONT_NUM.value])
            return[(feat[TagsLayer.ADMINISTRATIVE_ADDRESS.value], feat[TagsLayer.PARCEL_NR.value], feat[TagsLayer.AREA_USE_DIC_CONT_NUM.value], self.convert_to_gml(feat)) for feat in layer.getFeatures()]
        except Exception as e:
            raise e    
        
    def get_county_geometries(self,name: str):
        """Zwraca obiekty geometrii oddziałów"""
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            #layer=dataset.ExecuteSQL(sql)
            layer = self.get_first_layer(name)
            layer=self.get_collect_feature(layer, [TagsLayer.ADDRESS.value])
            #layer = dataset.GetLayer()
            #knieczna zmiana zwiazana z schematem (w schemacie jest nowsza wersja gdal niz w qgis)
            #'MultiPolygon' => 'MultiSurface' i 'polygonMember'=>'surfaceMember' dla obiektów typu multipolygon
            return [ Geom(feature[TagsLayer.ADDRESS.value],self.convert_to_gml(feature)) for feature in layer.getFeatures()]
            
        except Exception as e:
            raise e
        
    def get_basic_objects_geometries(self,name: str):
        """Zwraca geometrię obiektów podstawowych"""
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            #layer=dataset.ExecuteSQL(sql)
            layer=layer = self.get_first_layer(name)
            layer=self.get_collect_feature(layer, [TagsLayer.ADDRESS.value,
                                                   TagsLayer.ADMINISTRATIVE_ADDRESS.value,
                                                   TagsLayer.PARCEL_NR.value,
                                                   TagsLayer.AREA_USE_DIC_CONT_NUM.value])
            return[BasicObjectGeom(feature[TagsLayer.ADDRESS.value],feature[TagsLayer.PARCEL_NR.value],feature[TagsLayer.AREA_USE_DIC_CONT_NUM.value],self.convert_to_gml(feature)) for feature in layer.getFeatures()]
        except Exception as e:
            raise e
        
    def get_label_geometries(self,name: str):
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            layer = self.get_first_layer(name)#dataset.ExecuteSQL(sql)
            return [Geom(feature[TagsLayer.ADDRESS.value],self.convert_to_gml(feature)) for feature in layer.getFeatures()]
        except Exception as e:
            raise e
        
    def get_line_geometries(self,name: str):
        try:
            #dataset = self.driver.Open(path_to_shapefile)
            #layer = dataset.GetLayer()
            layer = self.get_first_layer(name)
            layer=self.get_collect_feature(layer, [TagsLayer.TYPE_CD.value,
                                                   TagsLayer.WIDTH.value])
            return [LineGeom(feature[TagsLayer.WIDTH.value],feature[TagsLayer.TYPE_CD.value],self.convert_to_gml(feature)) for feature in layer.getFeatures()]
        except Exception as e:
            raise e
        
    def get_collect_feature(self,layer:QgsVectorLayer, fields:[]):
        """Zwraca scalone polikony w multi parts p atrybutach fields"""
        try:
            collect_layer = processing.run("qgis:collect", {'INPUT':layer,'FIELD':fields,'OUTPUT':'memory:'})
            return collect_layer['OUTPUT']
        except Exception as e:
            raise e
        
    def get_first_layer(self,name:str)->QgsVectorLayer:
        """Zwraca pierwszą warstwę o nazwie name"""
        try:
            layer_list = QgsProject.instance().mapLayersByName(name)
            if layer_list:
                return layer_list[0]
            else:
                return None
        except Exception as e:
            raise e
        
    def convert_to_gml(self,feature:QgsFeature)->str:
        """Konvertuje geometrię na ciąg XML
        :param geometry: Geometria
        """
        try:
            geometry=feature.geometry()
            g=ogr.CreateGeometryFromJson(geometry.asJson())
            return g.ExportToGML().replace('MultiPolygon','MultiSurface').replace('polygonMember','surfaceMember')
        except Exception as e:
            raise e