import overpy
import geojson

'''
Módulo para descargar capa de Open Street Map y guardarlo como GeoJSON
'''

'''
                            1. Hago la búsqueda
- Todas las posibles etiquetas para filtrar la búsqueda:
        https://wiki.openstreetmap.org/wiki/Map_Features#Transportation
'''
#api = overpy.Overpass()

# # ejemplo 1 --> casas en LA
# q = api.query(("""
# (way(33.954289,-118.374724,33.968740,-118.344984)["building"];
#  rel(33.954289,-118.374724,33.968740,-118.344984)["building"];);
# (._;>;);
# out;
# """))


# ejemplo 2 --> parques en Madrid
# q = api.query(("""
# (way(40.403988,-3.7071133,40.426533,-3.6697769)["leisure"="park"];
# rel(40.403988,-3.7071133,40.426533,-3.6697769)["leisure"="park"];);
# (._;>;);
# out;
# """))

# ejemplo 3 --> water bodies en Madrid
#q = api.query(('''
#(way(40.403988,-3.7071133,40.426533,-3.6697769)['natural'='water'];
#rel(40.403988,-3.7071133,40.426533,-3.6697769)['natural'='water'];);
#(._;>;);
#out;
#'''))

# ejemplo 4 --> zonas residenciales
# q = api.query(('''
# (way(40.403988,-3.7071133,40.426533,-3.6697769)['landuse'='residential'];
# rel(40.403988,-3.7071133,40.426533,-3.6697769)['landuse'='residential'];);
# (._;>;);
# out;
# '''))

'''
                            2. Exportar una búsqueda en formato geojson
'''


def export_geojson(q, name_file,osmsubtype):  # donde q es el query hecho con overpy y name_file el directorio donde exportar
    print(name_file)
    features = []  # necesario para exportar como geojson
    '''
    Polígonos:
        Hay 2 posibilidades:
            -Ways que empiezan y acaban en el mismo punto
            -Relations donde el primer punto del primer way es el mismo que el último punto del último way
                -Formado por un polígono exterior y polígonos interiores (agujeros)
                    -Los ways del polígono exterior contienen la etiqueta "outer"
                    -Los ways de los polígonos interiores contienen la etiqueta "inner"
    '''
    # Caso 1: relations
    for relation in q.relations:
        print('relation')
        coordenadas_outer = []
        coordenadas_inners = []
        coordenadas_relway =[]
        for elemento in relation.members:
            if elemento._type_value == "way":  # puede haber tambíen puntos
                #print(elemento.ref)
                way = q.get_way(elemento.ref)
                coordenadas_way = [(float(node.lon), float(node.lat)) for node in way.get_nodes()]
                if elemento.role == "outer":
                    coordenadas_outer.append(coordenadas_way)
                    
                elif elemento.role == "inner":
                    coordenadas_inners.append(coordenadas_way)
                    
                elif elemento.role == None:
                    coordenadas_relway.append(coordenadas_way)
                    #we have to delete the ways because we are procesing later the ways individualy so we are going to do other time the same way
                    '''
                    for node in way.get_nodes():
                        coordenadas_relway.append([float(node.lon), float(node.lat)]) 
                    '''
                    
        '''
        Los multipolígonos tienen el formato [[.......],[...],...,[...]]. Donde la primera lista es el outer y el resto los inners
            -Para el outer tenemos que juntar todas las listas contenidas en coordenadas_outer:
                -Hay que tener cuidado porque algunas vienen dadas la vuelta
                    -Hay que comprobar que el último punto de uno es el primero del siguiente
                    -Y quitar uno de ellos para que no haya repeticiones
        '''
        if coordenadas_outer!=[]:
            while coordenadas_outer !=[]:
                coord1=coordenadas_outer[0][0]
                coord2=coordenadas_outer[0][-1]
                ways_ordenadas_rel=[]
                ways_ordenadas_rel.append(coordenadas_outer[0])
                coordenadas_outer.pop(0)
                len1=range(len(coordenadas_outer))
            
                for i in len1:
                    if any(e[-1]==coord1 for e in coordenadas_outer)==True:
                        x=next(coordenadas_outer.index(e) for e in coordenadas_outer if e[-1]==coord1)
                        coord1=coordenadas_outer[x][0]
                        ways_ordenadas_rel.insert(0,coordenadas_outer[x]) 
                        coordenadas_outer.pop(x)
                    elif any(e[0]==coord1 for e in coordenadas_outer)==True:
                        x=next(coordenadas_outer.index(e) for e in coordenadas_outer  if e[0]==coord1)
                        coord1=coordenadas_outer[x][-1]
                        ways_ordenadas_rel.insert(0,coordenadas_outer[x][::-1]) 
                        coordenadas_outer.pop(x)
                    else:
                        print(len(coordenadas_outer))
                        break

                len2=range(len(coordenadas_outer))
                for i in len2:
                    if any(e[0]==coord2 for e in coordenadas_outer)==True:
                        x=next(coordenadas_outer.index(e) for e in coordenadas_outer if e[0]==coord2)
                        coord2=coordenadas_outer[x][-1]
                        ways_ordenadas_rel.append(coordenadas_outer[x]) 
                        coordenadas_outer.pop(x)
                    elif any(e[-1]==coord2 for e in coordenadas_outer)==True:
                        x=next(coordenadas_outer.index(e) for e in coordenadas_outer  if e[-1]==coord2)
                        coord2=coordenadas_outer[x][0]
                        ways_ordenadas_rel.append(coordenadas_outer[x][::-1]) 
                        coordenadas_outer.pop(x)
                    else:
                        print(len(coordenadas_outer))
                        break

                print(len(coordenadas_outer))
                
                coordenadas_relation=[]
                for small in ways_ordenadas_rel:
                    [coordenadas_relation.append(small2) for small2 in small]

            
            # añado a features para poder exportar
            poligono = geojson.Polygon(coordenadas_relation)
            features.append(geojson.Feature(geometry=poligono, properties=relation.tags,
                                            id=relation._type_value+"/"+str(relation.id)))
        '''
        elif coordenadas_relway!=[]:
            while coordenadas_relway !=[]:
                coord1=coordenadas_relway[0][0]
                coord2=coordenadas_relway[0][-1]
                ways_ordenadas_rel=[]
                ways_ordenadas_rel.append(coordenadas_relway[0])
                coordenadas_relway.pop(0)
                len3=range(len(coordenadas_relway))

                for i in len3:
                    if any(e[-1]==coord1 for e in coordenadas_relway)==True:
                        x=next(coordenadas_relway.index(e) for e in coordenadas_relway if e[-1]==coord1)
                        coord1=coordenadas_relway[x][0]
                        ways_ordenadas_rel.insert(0,coordenadas_relway[x]) 
                        coordenadas_relway.pop(x)
                    elif any(e[0]==coord1 for e in coordenadas_relway)==True:
                        x=next(coordenadas_relway.index(e) for e in coordenadas_relway  if e[0]==coord1)
                        coord1=coordenadas_relway[x][-1]
                        ways_ordenadas_rel.insert(0,coordenadas_relway[x][::-1]) 
                        coordenadas_relway.pop(x)
                    else:
                        print(len(coordenadas_relway))
                        break

                    len4=range(len(coordenadas_relway))
                    for i in len4:
                        if any(e[0]==coord2 for e in coordenadas_relway)==True:
                            x=next(coordenadas_relway.index(e) for e in coordenadas_relway if e[0]==coord2)
                            coord2=coordenadas_relway[x][-1]
                            ways_ordenadas_rel.append(coordenadas_relway[x]) 
                            coordenadas_relway.pop(x)
                        elif any(e[-1]==coord2 for e in coordenadas_relway)==True:
                            x=next(coordenadas_relway.index(e) for e in coordenadas_relway  if e[-1]==coord2)
                            coord2=coordenadas_relway[x][0]
                            ways_ordenadas_rel.append(coordenadas_relway[x][::-1]) 
                            coordenadas_relway.pop(x)
                        else:
                            print(len(coordenadas_relway))
                            break

                print(len(coordenadas_relway))

                coordenadas_way_relation=[]
                for small in ways_ordenadas_rel:
                    [coordenadas_way_relation.append(small2) for small2 in small]

            line = geojson.LineString(coordenadas_way_relation)

            features.append(geojson.Feature(geometry=line, properties=relation.tags,
                                            id=relation._type_value+"/"+str(relation.id)))
        '''
    # Caso 2: ways
    ways_eval=[]
    ways_ref=[]
    ways=[]
    
    for way in q._ways.values():
        coordenadas = [(float(node.lon), float(node.lat)) for node in way.get_nodes()]
        if coordenadas[0] == coordenadas[-1]:  # si el primer punto y el último son iguales -> polígono
            print('polygon-way')
            # añado a features para poder exportar
            poligono = geojson.Polygon(coordenadas)
            features.append(geojson.Feature(geometry=poligono, properties=way.tags, id=way._type_value+"/"+str(way.id)))
        
        else:
            p=False
            for tag in way.tags:
                if way.tags[tag]== osmsubtype:
                    p=True
            i=0
            if p==True:
                for tag in way.tags:
                    i=i+1
                    number_tags=len(way.tags)
                    #we add way to the corresponding vector type
                    #we have two lists:
                        #1. in which we have a list with all the types of ref
                        #2. in wich we have a relation of all the ways and the ref at which corresponds
                    if tag == 'ref':
                        ref=way.tags[tag]
                        if ref in ways_ref:
                            index_ref= ways_ref.index(ref)
                            vec=[index_ref,way]
                            ways.append(vec) 
                        else:
                            ways_ref.append(ref)
                            index_ref= ways_ref.index(ref)
                            vec=[index_ref,way]
                            ways.append(vec)
                        p=False


                    elif tag == 'name':
                        ref=way.tags[tag]
                        if ref in ways_ref:
                            index_ref= ways_ref.index(ref)
                            vec=[index_ref,way]
                            ways.append(vec) 
                        else:
                            ways_ref.append(ref)
                            index_ref= ways_ref.index(ref)
                            vec=[index_ref,way]
                            ways.append(vec)
                        p=False
                          
                          
                    elif i==number_tags and p==True:
                        Line = geojson.LineString(coordenadas)
                        features.append(geojson.Feature(geometry=Line, properties=way.tags, id=way.id)) 

                    '''
                    elif i==len(way.tags):
                        ref=''
                        if ref in ways_ref:
                          index_ref= ways_ref.index(ref)
                          vec=[index_ref,way]
                          ways.append(vec) 
                        else:
                          ways_ref.append(ref)
                          index_ref= ways_ref.index(ref)
                          vec=[index_ref,way]
                          ways.append(vec)
                    '''
                    

        

    #Now we have to evaluated this lists and organize it 
    for j in range(len(ways_ref)):
        for w in ways:
            if w[0]==j: 
                ways_eval.append(w[1])
        while ways_eval:
            print('new line')
            coord1=ways_eval[0].nodes[0]
            coord2=ways_eval[0].nodes[-1]
            prop=ways_eval[0].tags
            ids=ways_eval[0]._type_value+"/"+str(ways_eval[0].id)
            ways_ordenadas=[]
            ways_ordenadas.append(ways_eval[0].nodes)
            ways_eval.pop(0)
            len1=range(len(ways_eval))
        
            for i in len1:
                if any(e.nodes[-1]==coord1 for e in ways_eval)==True:
                    x=next(ways_eval.index(e) for e in ways_eval if e.nodes[-1]==coord1)
                    coord1=ways_eval[x].nodes[0]
                    ways_ordenadas.insert(0,ways_eval[x].nodes) 
                    ways_eval.pop(x)
                elif any(e.nodes[0]==coord1 for e in ways_eval)==True:
                    x=next(ways_eval.index(e) for e in ways_eval if e.nodes[0]==coord1)
                    coord1=ways_eval[x].nodes[-1]
                    ways_ordenadas.insert(0,ways_eval[x].nodes[::-1]) 
                    ways_eval.pop(x)
                else:
                    print(len(ways_eval))
                    break



            len2=range(len(ways_eval))
            for i in len2:
                if any(e.nodes[0]==coord2 for e in ways_eval)==True:
                    x=next(ways_eval.index(e) for e in ways_eval if e.nodes[0]==coord2)
                    coord2=ways_eval[x].nodes[-1]
                    ways_ordenadas.append(ways_eval[x].nodes) 
                    ways_eval.pop(x)

                elif any(e.nodes[-1]==coord2 for e in ways_eval)==True:
                    x=next(ways_eval.index(e) for e in ways_eval if e.nodes[-1]==coord2)
                    coord2=ways_eval[x].nodes[0]
                    ways_ordenadas.append(ways_eval[x].nodes[::-1]) 
                    ways_eval.pop(x)
                else:
                    print(len(ways_eval))
                    break 

            print(len(ways_eval))

            coordinates_ways_ord=[]
            for small_way in ways_ordenadas:
                coordenadas_small_way = [(float(node.lon), float(node.lat)) for node in small_way]
                [coordinates_ways_ord.append(coord) for coord in coordenadas_small_way]
            
            Line = geojson.LineString(coordinates_ways_ord)
            features.append(geojson.Feature(geometry=Line, properties=prop, id=ids))
        



       
        
        
        
         

#we have to append the coords as individual points, not vectors 

#feature_way= geojson.LineString(new_ways_coords)
#features.append(geojson.Feature(geometry=feature_way, properties=w.tags, id=w._type_value+"/"+str(w.id)))


    
    #Caso 3:points
    for points in q.get_nodes():
        for tag in points.tags:
            if points.tags[tag]== osmsubtype:
                print('it is a point', points.tags[tag])
                coordenadas = [float(points.lon), float(points.lat)]
                feature_point= geojson.Point(coordenadas)
                features.append(geojson.Feature(geometry=feature_point, properties=points.tags, id=points._type_value+"/"+str(points.id)))

        



    # guardo el resultado como geojson
    feature_collection = geojson.FeatureCollection(features)  # necesario para exportar como geojson
    with open('environments/osm/geojson2/{}.geojson'.format(name_file), 'w') as f:
        geojson.dump(feature_collection, f)
