from axipy import Notifications
from osgeo import ogr, osr

from rosreestrXml.ui.tools.KPT.kptTools.DbKptDirectory import KptСatalog
from rosreestrXml.ui.tools.forest.ForestDeclaration.forestDeclaration import parseString


def createOgrObject(list_points):
    type_obj=ogr.wkbLineString
    if len(list_points)<=2:
        type_obj =ogr.wkbLineString
    pnt_start=list_points[0]
    pnt_end=list_points[-1]
    if pnt_end['numberEnd']==pnt_start['numberBegin']:
        type_obj=ogr.wkbLinearRing
    ogr_obj= ogr.Geometry(type_obj)
    #ogr_obj.AddPoint(pnt_start['longitude'],pnt_start['latitude'])
    count_point=len(list_points)
    for pnt in list_points:
        ogr_obj.AddPoint(pnt['longitude'], pnt['latitude'])
    if type_obj==ogr.wkbLinearRing:
        ogr_obj.AddPoint(pnt_start['longitude'],pnt_start['latitude'])
        obj_polygon=ogr.Geometry(ogr.wkbPolygon)
        obj_polygon.AddGeometry(ogr_obj)
        return obj_polygon
    return ogr_obj
def createOgrObjectMulti(list_points):
    if len(list_points)==1:
        return createOgrObject(list_points[0])
    geo_result=ogr.Geometry(ogr.wkbMultiPolygon)
    for points in list_points:
        geo_poly=createOgrObject(points)
        if geo_poly is None:
            continue
        geo_result.AddGeometry(geo_poly)
        geo_poly=None
    return geo_result
class LocationPoints:
    __name = 'forest_location_points'
    __nameProcess = 'Импорт каталога точек'
    def __init__(self,tagExplication,propertis):
        self.__tagBase=tagExplication
        self.__properties=propertis
        self.__subforestry_id = None
        self.__forestry_id = None
        self.build()
        self.__preparePoints()
        self.__cs_wkt_default = 'GEOGCS["unnamed",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563],TOWGS84[0,0,0,0,0,0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]]'
        self.__cs_mi_default = 'Earth Projection 1, 104'
    def setParentsId(self,forestry_id,subforestry_id):
        self.__subforestry_id=subforestry_id
        self.__forestry_id=forestry_id
        for pnt in self.__points_source:
            pnt['forestry_id']=forestry_id
            pnt['subforestry_id'] = subforestry_id
    def setStyle(self,mi_stile):
        self.__mi_style=mi_stile
    @property
    def NameLayer(self):
        return self.__name

    @property
    def NameProcess(self):
        return self.__nameProcess

    @staticmethod
    def getStruct():
        struct = []
        struct.append({'name': 'forestry_id', 'type': ogr.OFTString, 'width': 12})
        struct.append({'name': 'subforestry_id', 'type': ogr.OFTString, 'width': 12})
        struct.append({'name': 'objectNumber', 'type': ogr.OFTInteger})
        struct.append({'name': 'numberBegin', 'type': ogr.OFTInteger})
        struct.append({'name': 'numberEnd', 'type': ogr.OFTInteger})
        #struct.append({'name': 'lineDirection', 'type': ogr.OFTReal})
        struct.append({'name': 'lineDirection', 'type': ogr.OFTString, 'width': 24})
        struct.append({'name': 'lineLength', 'type': ogr.OFTReal})
        struct.append({'name': 'longitude', 'type': ogr.OFTReal})
        struct.append({'name': 'latitude', 'type': ogr.OFTReal})
        return struct
    def build(self):
        self.__points_source=[]
        data_types=self.getStruct()
        for pnt in self.__tagBase.row:
            values={}
            for item in data_types:
                if item['name']=='forestry_id':
                    continue
                if item['name']=='subforestry_id':
                    continue
                value=getattr(pnt,item['name'])
                if item['name']=="lineDirection":
                    jkl=0
                if item['type']==ogr.OFTReal:
                    if isinstance(value,str):
                        value_str=value
                        if len(value)==0:
                            value=0
                        else:
                            try:
                                value=float(value.replace(',','.'))
                            except:
                                value=-360

                                Notifications.push('Предупреждение Xml конвертор', 'Ошибка преобразования '+item['name']+':'+value_str+" в число ", Notifications.Warning)
                    else:
                        try:
                            value = float(value)
                        except:
                            print('Отсутствует значение ' + item['name']  )
                            value=0
                if item['type'] == ogr.OFTInteger:
                    try:
                        value = int(value)
                    except:
                        value=0
                values[item['name']]=value
            self.__points_source.append(values)
        return len(self.__points_source)
    def __preparePoints(self):
        self.__points=[]
        curent_poly=[]
        for i,pnt in enumerate(self.__points_source):
            curent_poly.append(pnt)
            list_pnt=list(filter(lambda pnt_x: pnt_x['numberBegin'] == pnt['numberEnd'],curent_poly))
            if len(list_pnt)>0:
                self.__points.append(curent_poly)
                curent_poly = []
        jkl=0




    def getPoints(self):
        return self.__points
    def CreateLayer(self, ds, createNewLayer=True):

        layer = None
        if not createNewLayer:
            layer = ds.GetLayer(self.__name)
            if layer is not None:
                return layer
        srs = osr.SpatialReference()

        srs.ImportFromWkt(self.__cs_wkt_default)
        layer = ds.CreateLayer(self.__name, srs, geom_type=ogr.wkbUnknown)
        for fld in LocationPoints.getStruct():
            # create fields
            field_cur = ogr.FieldDefn(fld['name'], fld['type'])
            type_field = fld['type']
            if fld['type'] == ogr.OFTString:
                field_cur.SetWidth(fld['width'])
            layer.CreateField(field_cur)
        field_cur = ogr.FieldDefn('MI_STYLE', ogr.OFTString)
        field_cur.SetWidth(128)
        layer.CreateField(field_cur)
        return layer

    def Write(self, layer, dbDictionary: KptСatalog=None, mapCatalog=None):
        for pnt in self.__points_source:
            self.__writePoint(layer,pnt)

    def __writePoint(self,layer,pnt):
        att = []
        for name in list(pnt.keys()):
            att.append({'name': name, 'value': pnt[name]})
        att.append({'name': 'MI_STYLE', 'value': self.__mi_style})
        feature = ogr.Feature(layer.GetLayerDefn())
        for atr_item in att:
            try:
                feature.SetField(atr_item['name'], atr_item['value'])
            except Exception as ex:
                pass
        geo_obj=ogr.Geometry(ogr.wkbPoint)
        geo_obj.AddPoint(pnt['longitude'],pnt['latitude'])

        if geo_obj is not None:
            feature.SetGeometry(geo_obj)
        layer.CreateFeature(feature)
        geo_obj = None
        feature = None
        return


class ObjLocation:
    __name = 'forest_location'
    __nameProcess = 'Импорт объектов'

    def __init__(self, tagRow,properties,properties_point):
        self.__tagBase=tagRow
        self.__properties=properties
        self.__objPoints=LocationPoints(tagRow.explication,properties_point)
        self.__cs_wkt_default = 'GEOGCS["unnamed",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563],TOWGS84[0,0,0,0,0,0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]]'
        self.__cs_mi_default = 'Earth Projection 1, 104'
        try:
            obj_location = self.__tagBase.location
            forest_id = obj_location.forestry.id

            subforestry_id = obj_location.subforestry.id
            self.__objPoints.setParentsId(forest_id,subforestry_id)
        except:
            pass
    def setStyle(self,mi_stile):
        self.__mi_style=mi_stile
    @property
    def NameLayer(self):
        return self.__name

    @property
    def NameProcess(self):
        return self.__nameProcess
    @staticmethod
    def getStruct():
        struct = []

        struct.append({'name': 'forestry_id', 'type': ogr.OFTString, 'width': 12})
        struct.append({'name': 'forestry_name', 'type': ogr.OFTString, 'width': 120})
        struct.append({'name': 'subforestry_id', 'type': ogr.OFTString, 'width': 12})
        struct.append({'name': 'subforestry_name', 'type': ogr.OFTString, 'width': 120})
        struct.append({'name': 'tract_id', 'type': ogr.OFTString, 'width': 12})
        struct.append({'name': 'tract_name', 'type': ogr.OFTString, 'width': 120})
        struct.append({'name': 'quarter', 'type':ogr.OFTString, 'width': 120})
        struct.append({'name': 'taxationUnit', 'type': ogr.OFTString, 'width': 120})
        struct.append({'name': 'objectNumber', 'type': ogr.OFTInteger})
        return struct
    @property
    def Points(self):
        return self.__objPoints
    def Write(self, layer, dbDictionary: KptСatalog, mapCatalog=None):
        att = []
        obj_location=self.__tagBase.location
        forest_id=obj_location.forestry.id
        forestry_name=obj_location.forestry.name
        subforestry_id=obj_location.subforestry.id
        subforestry_name=obj_location.subforestry.name
        tract_id=obj_location.tract.id
        tract_name = obj_location.tract.name
        quarter=obj_location.quarter
        taxationUnit=obj_location.taxationUnit
        objectNumber=self.__tagBase.objectNumber
        att.append({'name': 'forestry_id', 'value': forest_id})
        att.append({'name': 'forestry_name', 'value': forestry_name})
        att.append({'name': 'subforestry_id', 'value': subforestry_id})
        att.append({'name': 'subforestry_name', 'value': subforestry_name})
        att.append({'name': 'tract_id', 'value': tract_id})
        att.append({'name': 'tract_name', 'value': tract_name})
        att.append({'name': 'quarter', 'value': quarter})
        att.append({'name': 'taxationUnit', 'value': taxationUnit})
        att.append({'name': 'objectNumber', 'value': objectNumber})
        geo_obj=createOgrObjectMulti(self.__objPoints.getPoints())
        feature = ogr.Feature(layer.GetLayerDefn())
        att.append({'name': 'MI_STYLE', 'value':  self.__mi_style})
        for atr_item in att:
            try:
                feature.SetField(atr_item['name'], atr_item['value'])
            except Exception as ex:
                jkl = 0

        if geo_obj is not None:
            feature.SetGeometry(geo_obj)
        layer.CreateFeature(feature)
        geo_obj = None
        feature = None
        return
    def CreateLayer(self, ds, createNewLayer=True):

        layer = None
        if not createNewLayer:
            layer = ds.GetLayer(self.__name)
            if layer is not None:
                return layer
        srs = osr.SpatialReference()

        srs.ImportFromWkt( self.__cs_wkt_default)
        layer = ds.CreateLayer(self.__name, srs, geom_type=ogr.wkbUnknown)
        for fld in ObjLocation.getStruct():
            # create fields
            field_cur = ogr.FieldDefn(fld['name'], fld['type'])
            type_field = fld['type']
            if fld['type'] == ogr.OFTString:
                field_cur.SetWidth(fld['width'])
            layer.CreateField(field_cur)
        field_cur = ogr.FieldDefn('MI_STYLE', ogr.OFTString)
        field_cur.SetWidth(128)
        layer.CreateField(field_cur)
        return layer
class ObjLocations:
    __name = 'forest_location'
    __nameProcess = 'Импорт объектов'
    def __init__(self,tagBase,properties):
        self.__baseTag=tagBase
        self.__properties=properties
        self.__cs_wkt_default='GEOGCS["unnamed",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563],TOWGS84[0,0,0,0,0,0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]]'
        self.__cs_mi_default='Earth Projection 1, 104'
        self.__objLocation=None
        self.__initLocations()
    def __initLocations(self):
        self.__objLocation=[]
        for tagXml in self.__baseTag.row:
            self.__objLocation.append(ObjLocation(tagXml,self.__properties,None))
        return
    def getLocations(self):
        if len(self.__objLocation)==0:
            return None
        return self.__objLocation

    def getPoints(self):
        objPoints=[]
        for objLocation in self.__objLocation:
            objPnt=objLocation.Points
            if objPnt is None:
                continue
            objPoints.append(objPnt)
        if len(objPoints)==0:
            return None
        return objPoints
    def CreateLayer(self, ds, createNewLayer=True):

        layer = None
        if not createNewLayer:
            layer = ds.GetLayer(self.__name)
            if layer is not None:
                return layer
        srs = osr.SpatialReference()

        srs.ImportFromWkt(self.__cs_prj4)
        layer = ds.CreateLayer(self.__name, srs, geom_type=ogr.wkbUnknown)
        for fld in ObjLocation.getStruct():
            # create fields
            field_cur = ogr.FieldDefn(fld['name'], fld['type'])
            type_field = fld['type']
            if fld['type'] == ogr.OFTString:
                field_cur.SetWidth(fld['width'])
            layer.CreateField(field_cur)
        field_cur = ogr.FieldDefn('MI_STYLE', ogr.OFTString)
        field_cur.SetWidth(128)
        layer.CreateField(field_cur)
        return layer

    def Write(self, layer, dbDictionary: KptСatalog, mapCatalog=None):
        if self.__objLocation is None or len(self.__objLocation)==0:
            return
        ''' Получаем стиль из базы'''
        mi_style = dbDictionary.GetStyle('forest_declaration_style', 'location')
        if mi_style[0] is None:
            print(mi_style[1])
            str_mi_style = 'Pen (2, 6, 16711680) Brush (1, 16777215, 16777215)'
        else:
            str_mi_style = mi_style[0]
        for objLocation in self.__objLocation:
            objLocation.setMiStyle(str_mi_style)
            #if dbDoc is not None:
            #    if dbDoc.IsConnect is False:
            #        dbDoc.initDb()
            objLocation.Write(layer,dbDictionary,mapCatalog)
        mapCatalog.addLayerInfoInMapCataalog(layer, self.__cs_mi_default)
    @property
    def NameLayer(self):
        return self.__name

    @property
    def NameProcess(self):
        return self.__nameProcess

def ForestDeclarationObjFromString(source_xml, property=None):
    obj_Forest = parseString(source_xml, True)
    if obj_Forest is None:
        return None
    objLocations = ObjLocations(obj_Forest.locationInformation,property)
    objTosave=[]
    if property['points']['enable']:
        obj_points=objLocations.getPoints()
        if obj_points is not None:
            for obj_pnt in obj_points:
                obj_pnt.setStyle(property['points']['style'])
                objTosave.append(obj_pnt)
            #objTosave.extend(obj_points)
    if property['locations']['enable']:

        locations=objLocations.getLocations()
        if locations is not None:
            for location in locations:
                location.setStyle(property['locations']['style'])
                objTosave.append(location)
            #objTosave.extend(locations)
    if len(objTosave)==0:
        return None
    return objTosave










