import sys
from operator import itemgetter

from osgeo import ogr

#from rosreestrXml.ui.tools.kptTools.KptBound import addAtributDocuments

isAxioma=True
def valueCoord(xy):
    if isinstance(xy, str):
        return float(xy)
    return xy
class KptBound:
    __xmin=sys.float_info.max
    __ymin=sys.float_info.max
    __xmax=sys.float_info.min
    __ymax=sys.float_info.min
    def extend(self,x,y):
        self.__xmin=min(self.__xmin,x)
        self.__xmax=max(self.__xmax,x)
        self.__ymin=min(self.__ymin,y)
        self.__ymax=max(self.__ymax,y)
    @property
    def Xmin(self):
        return self.__xmin
    @property
    def Xmax(self):
        return self.__xmax
    @property
    def Ymin(self):
        return self.__ymin
    @property
    def Ymax(self):
        return self.__ymax


class KPTPoint:
    __x=None
    __y=None
    __suNmb=None
    __ordNmb=None
    def __init__(self,x,y,suNmb,ordNmb=1):
        self.__x=valueCoord(x)
        self.__y=valueCoord(y)
        self.__suNmb=suNmb
        self.__ordNmb=ordNmb
    @property
    def X(self):
        return self.__x
    @property
    def Y(self):
        return self.__y
def FactoryKPTPoint(tagpelementUnit):
    SuNmb=tagpelementUnit.SuNmb
    tagOrdinate=tagpelementUnit.Ordinate
    x=tagOrdinate.X
    y=tagOrdinate.Y
    OrdNmb=tagOrdinate.OrdNmb
    return KPTPoint(x,y,SuNmb,OrdNmb)
class KptSpatialElement:
    __points=[]
    __bound = KptBound()
    def __init__(self):
        self.__points=[]
        self.__bound=KptBound()
    def addPoint(self,kpt_point:KPTPoint):
        self.__bound.extend(kpt_point.X,kpt_point.Y)
        self.__points.append(kpt_point)
    @property
    def Points(self):
        return self.__points
class SpatialData:
    __spatialElements=None
    __entCoordSys=None
    __bound=None
    __cadNumber=None
    __attribute=None
    def __init__(self,tagXmlSpatial,idCoordSys,cadNumber):
        self.__objXmlSpatial=tagXmlSpatial
        self.__entCoordSys=idCoordSys
        self.__spatialElements=[]
        self.__bound=KptBound()
        self.__cadNumber=cadNumber
    def addSpatialElement(self,objSpElement:KptSpatialElement):
        self.__spatialElements.append(objSpElement)
    @property
    def document(self):
        return self.__objXmlSpatial.Documents
    @property
    def Points(self):
        out_points=[]
        for sp in self.__spatialElements:
            out_points.append(sp.Points)
        return out_points
    @property
    def Attribute(self):
        attr=[]
        att_cadNum={}
        att_cadNum['name']='КадНомер'
        att_cadNum['value'] = self.__cadNumber
        attr.append(att_cadNum)
        if self.__attribute is not None:
            attr.extend(self.__attribute)
        return attr
    def setAttribute(self,attr):
        self.__attribute=attr
def FactorySpatialData(xml_tagSpatial,cadNumber):
    objDocs=xml_tagSpatial.Documents
    att_kpt={'name':'КадНомер','value':cadNumber}
    #objDocuments = objDocs.Document
    #from rosreestrXml.ui.tools.kptTools.KptBound import addAtributDocuments
    #att_kpt.extend(addAtributDocuments(objDocuments, dbCatalog))
    '''
    if objDocs is not None:
        #Извлекаем данные
        doc_1=objDocs.Document[0]
        valueCodeDocument=doc_1.CodeDocument
        valueName=doc_1.Name
        valueNumber=doc_1.Number
        valueDate=doc_1.Date
        valueIssueOrgan=doc_1.IssueOrgan
        att_kpt=[]
        att_1={}
        att_1['name']='код_документа'
        att_1['value']=valueCodeDocument
        att_kpt.append(att_1)
        att_2={}
        att_2['name']='название'
        att_2['value']=valueName
        att_kpt.append(att_2)
        att_3={}
        att_3['name']='Номер_документа'
        att_3['value']=valueNumber
        att_kpt.append(att_3)
        att_date={}
        att_date['name']='Дата_выдачи'
        att_date['value']=str(valueDate)
        att_kpt.append(att_date)
    '''
    objEntitySp=xml_tagSpatial.EntitySpatial
    objSpatialData=SpatialData(xml_tagSpatial,objEntitySp.EntSys,cadNumber)
    objSpatialElement=objEntitySp.SpatialElement
    for spElement in objSpatialElement:
        objSpelementUnit=spElement.SpelementUnit
        objSpElement=KptSpatialElement()
        for tagpoint in objSpelementUnit:
            point=FactoryKPTPoint(tagpoint)
            objSpElement.addPoint(point)
        objSpatialData.addSpatialElement(objSpElement)
    objSpatialData.setAttribute(att_kpt)
    return objSpatialData
def PrepareArrayPolygon(polygons):

    arrayPolygons=[]
    for polygon in polygons:
        plarea=polygon.GetArea()
        arrayPolygons.append([polygon,plarea])
    ''' Sort on Area'''
    arrayPolygons.sort(key=itemgetter(1))
    countPolygon=len(polygons)
    for i in range(0,countPolygon-1):

        cur_poly=arrayPolygons[i][0]
        if i>=273:
            jkl=0
        for j in range(i+1,countPolygon):
            next_poly = arrayPolygons[j ][0]
            isContain=next_poly.Contains(cur_poly)
            if isContain :
                ''' next poly содержит в себе cur_poly'''

                '''countRing=cur_poly.GetGeometryCount()
                for k in range(countRing):
                    next_poly.AddGeometry(cur_poly.GetGeometryRef(k))
                '''
                new_poly=next_poly.Difference(cur_poly)
                cur_poly=None
                next_poly=None
                arrayPolygons[i][0]=None
                arrayPolygons[j][0]=new_poly
                break
    result_polygon=[]
    for rec_poly in arrayPolygons:
        if rec_poly[0] is not None:
            result_polygon.append(rec_poly[0])
            rec_poly[0]=None
    return result_polygon
def GeoPolygonFromEntitySpatial(xmlTagEntitySpatial,reverseXY=False):
    if xmlTagEntitySpatial is None:
        return None
    geoPolyon=[]
    for itemPoints in xmlTagEntitySpatial.SpatialElement:
        ring = ogr.Geometry(ogr.wkbLinearRing)
        for itemPoint in itemPoints.SpelementUnit:
            x = float(itemPoint.Ordinate.X)
            y = float(itemPoint.Ordinate.Y)
            if reverseXY :
                ring.AddPoint(y,x)
            else:
                ring.AddPoint(x, y)
        poly = ogr.Geometry(ogr.wkbPolygon)
        poly.AddGeometry(ring)
        geoPolyon.append(poly)
    if len(geoPolyon)<=1:
        return geoPolyon[0]
    prep_polygons=PrepareArrayPolygon(geoPolyon)
    multipolygon = ogr.Geometry(ogr.wkbMultiPolygon)
    #for poly in geoPolyon:
    for poly in prep_polygons:
        multipolygon.AddGeometry(poly)
    return multipolygon
def EqPoint(point_start,point_end):
    x0=point_start.Ordinate.X
    y0=point_start.Ordinate.Y
    x1 = point_end.Ordinate.X
    y1 = point_end.Ordinate.Y
    if x0!=x1:
        return False
    if y0!=y1:
        return False
    return True
def GeoPolylineFromEntitySpatial(xmlTagEntitySpatial,reverseXY=True):
    if xmlTagEntitySpatial is None:
        return None
    geoList=[]
    for itemPoints in xmlTagEntitySpatial.SpatialElement:
        curGeoObj=ogr.Geometry(ogr.wkbLineString)
        for itemPoint in itemPoints.SpelementUnit:
            x = float(itemPoint.Ordinate.X)
            y = float(itemPoint.Ordinate.Y)
            if reverseXY :
                curGeoObj.AddPoint(y,x)
            else:
                curGeoObj.AddPoint(x, y)

        geoList.append(curGeoObj)
    if len(geoList)==1:
        return geoList[0]
    geomcol = ogr.Geometry(ogr.wkbGeometryCollection)
    for itemGeo in geoList:
        geomcol.AddGeometry(itemGeo)
    return geomcol
def GeoBuilderFromEntitySpatial(xmlTagEntitySpatial,reverseXY=True):
    if xmlTagEntitySpatial is None:
        return None
    geoList=[]
    for itemPoints in xmlTagEntitySpatial.SpatialElement:
        sizeGeo=len(itemPoints.SpelementUnit)
        if sizeGeo==1:
            ''' Возможно окружность'''
            jk=0
            nameType=itemPoints.SpelementUnit[0].TypeUnit
            if nameType=="Окружность":
                r=float(itemPoints.SpelementUnit[0].R)
                point = ogr.Geometry(ogr.wkbPoint)
                x = float(itemPoints.SpelementUnit[0].Ordinate.X)
                y = float(itemPoints.SpelementUnit[0].Ordinate.Y)
                if reverseXY:
                    point.AddPoint(y, x)
                else:
                    point.AddPoint(x, y)

                curGeoObj=point.Buffer(r)
                geoList.append(curGeoObj)
            continue
        point_start=itemPoints.SpelementUnit[0]
        point_end=itemPoints.SpelementUnit[sizeGeo-1]
        curGeoObj=None
        if EqPoint(point_start,point_end):
            curGeoObj =ogr.Geometry(ogr.wkbLinearRing)
        else:
            curGeoObj=ogr.Geometry(ogr.wkbLineString)
        for itemPoint in itemPoints.SpelementUnit:
            x = float(itemPoint.Ordinate.X)
            y = float(itemPoint.Ordinate.Y)
            if reverseXY :
                curGeoObj.AddPoint(y,x)
            else:
                curGeoObj.AddPoint(x, y)
        if curGeoObj.GetGeometryName()=="LINEARRING":
            poly = ogr.Geometry(ogr.wkbPolygon)
            poly.AddGeometry(curGeoObj)
            geoList.append(poly)
        else:
            geoList.append(curGeoObj)
    if len(geoList)==1:
        return geoList[0]
    geomcol = ogr.Geometry(ogr.wkbGeometryCollection)
    for itemGeo in geoList:
        geomcol.AddGeometry(itemGeo)
    return geomcol
class ObjEntitySpatial:
    __points = []
    __bound = KptBound()
    __objXml=None
    __strXmlCoordSys=None
    def __init__(self,xmlTagEntitySpatial):
        self.__objXml=xmlTagEntitySpatial
        self.prepareSpatial()

    def prepareSpatial(self):
        self.__strXmlCoordSys=self.__objXml.EntSys
        objSpatialElement=self.__objXml.SpatialElement
        for itemPoints in objSpatialElement:
            for itemPoint in itemPoints.SpelementUnit:
                x=itemPoint.Ordinate.X
                y=itemPoint.Ordinate.Y





