from .util_io import getFileHandle
from .. import settings as og_settings
from shapely import wkt
import os
import csv


def _outputMesoNodes(mesonet, mesonode_filepath, projection, encoding):
    outfile = getFileHandle(mesonode_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['node_id', 'zone_id', 'x_coord', 'y_coord', 'macro_node_id', 'macro_link_id', 'activity_type', 'is_boundary'])
    for _, mesonode in mesonet.node_dict.items():
        if projection:
            x_coord = round(mesonode.geometry_xy.x, og_settings.local_coord_precision)
            y_coord = round(mesonode.geometry_xy.y, og_settings.local_coord_precision)
        else:
            x_coord = round(mesonode.geometry.x, og_settings.lonlat_coord_precision)
            y_coord = round(mesonode.geometry.y, og_settings.lonlat_coord_precision)

        line = [mesonode.node_id, mesonode.zone_id, x_coord, y_coord, mesonode.macro_node_id, mesonode.macro_link_id,
                mesonode.activity_type, mesonode.is_boundary]
        writer.writerow(line)

    outfile.close()


def _outputMesoLinks(mesonet, mesolink_filepath, projection, encoding):
    outfile = getFileHandle(mesolink_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['link_id', 'from_node_id', 'to_node_id', 'dir_flag', 'length', 'lanes', 'capacity',
                     'free_speed', 'link_type_name', 'link_type', 'geometry', 'macro_link_id', 'macro_node_id',
                     'movement_id', 'mvmt_txt_id', 'ctrl_type', 'allowed_uses'])
    for _, mesolink in mesonet.link_dict.items():
        if projection:
            geometry_ = wkt.dumps(mesolink.geometry_xy, rounding_precision=og_settings.local_coord_precision)
        else:
            geometry_ = wkt.dumps(mesolink.geometry, rounding_precision=og_settings.lonlat_coord_precision)

        line = [mesolink.link_id, mesolink.from_node.node_id, mesolink.to_node.node_id, mesolink.dir_flag, mesolink.length,
                mesolink.lanes, mesolink.capacity, mesolink.free_speed, mesolink.link_type_name,mesolink.link_type,
                geometry_, mesolink.macro_link_id, mesolink.macro_node_id,  mesolink.movement_id, mesolink.mvmt_txt_id, mesolink.ctrl_type,
                ';'.join(mesolink.allowed_uses) if mesolink.allowed_uses else '']
        writer.writerow(line)

    outfile.close()


def _outputMicroNodes(micronet, micronode_filepath, projection, encoding):
    outfile = getFileHandle(micronode_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['node_id', 'zone_id', 'x_coord', 'y_coord', 'meso_link_id', 'lane_no', 'is_boundary'])
    for _, micronode in micronet.node_dict.items():
        if projection:
            x_coord = round(micronode.geometry_xy.x, og_settings.local_coord_precision)
            y_coord = round(micronode.geometry_xy.y, og_settings.local_coord_precision)
        else:
            x_coord = round(micronode.geometry.x, og_settings.lonlat_coord_precision)
            y_coord = round(micronode.geometry.y, og_settings.lonlat_coord_precision)

        line = [micronode.node_id, micronode.zone_id, x_coord, y_coord, micronode.mesolink.link_id, micronode.lane_no, micronode.is_boundary]
        writer.writerow(line)

    outfile.close()


def _outputMicroLinks(micronet, microlink_filepath, projection, encoding):
    outfile = getFileHandle(microlink_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['link_id', 'from_node_id', 'to_node_id', 'dir_flag', 'length', 'lanes', 'capacity',
                     'free_speed', 'link_type_name', 'link_type', 'geometry', 'macro_node_id', 'macro_link_id',
                     'meso_link_id', 'cell_type', 'additional_cost', 'lane_no', 'mvmt_txt_id', 'ctrl_type', 'allowed_uses'])
    for _, microlink in micronet.link_dict.items():
        if projection:
            geometry_ = wkt.dumps(microlink.geometry_xy, rounding_precision=og_settings.local_coord_precision)
        else:
            geometry_ = wkt.dumps(microlink.geometry, rounding_precision=og_settings.lonlat_coord_precision)

        line = [microlink.link_id, microlink.from_node.node_id, microlink.to_node.node_id, microlink.dir_flag,
                microlink.length, 1, microlink.mesolink.capacity, microlink.mesolink.free_speed,
                microlink.mesolink.link_type_name, microlink.mesolink.link_type, geometry_,
                microlink.mesolink.macro_node_id, microlink.mesolink.macro_link_id, microlink.mesolink.link_id,
                microlink.cell_type, 0, microlink.lane_no, microlink.mvmt_txt_id, microlink.ctrl_type,
                ';'.join(microlink.allowed_uses) if microlink.allowed_uses else '']
        writer.writerow(line)

    outfile.close()


def outputMesoNet(mesonet, output_folder, prefix, projection, encoding):
    mesonet_folder = os.path.join(output_folder, 'mesonet')
    if not os.path.isdir(mesonet_folder): os.mkdir(mesonet_folder)

    mesonode_filepath = os.path.join(mesonet_folder, f'{prefix}node.csv')
    _outputMesoNodes(mesonet, mesonode_filepath, projection, encoding)

    mesolink_filepath = os.path.join(mesonet_folder, f'{prefix}link.csv')
    _outputMesoLinks(mesonet, mesolink_filepath, projection, encoding)


def outputMicroNet(micronet, output_folder, prefix, projection, encoding):
    micronet_folder = os.path.join(output_folder, 'micronet')
    if not os.path.isdir(micronet_folder): os.mkdir(micronet_folder)

    micronode_filepath = os.path.join(micronet_folder, f'{prefix}node.csv')
    _outputMicroNodes(micronet, micronode_filepath, projection, encoding)

    microlink_filepath = os.path.join(micronet_folder, f'{prefix}link.csv')
    _outputMicroLinks(micronet, microlink_filepath, projection, encoding)



def _outputMacroNodes(network, macronode_filepath, projection, encoding):
    outfile = getFileHandle(macronode_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['name', 'node_id', 'osm_node_id', 'osm_highway', 'zone_id', 'ctrl_type', 'node_type', 'activity_type',
                     'is_boundary', 'x_coord', 'y_coord', 'intersection_id','poi_id','notes'])
    for node_id, node in network.node_dict.items():
        if projection:
            x_coord = round(node.geometry_xy.x, og_settings.local_coord_precision)
            y_coord = round(node.geometry_xy.y, og_settings.local_coord_precision)
        else:
            x_coord = round(node.geometry.x, og_settings.lonlat_coord_precision)
            y_coord = round(node.geometry.y, og_settings.lonlat_coord_precision)
        line = [node.name, node.node_id, node.osm_node_id, node.osm_highway, node.zone_id, node.ctrl_type, '', node.activity_type,
                node.is_boundary, x_coord, y_coord, node.intersection_id, node.poi_id, node.notes]
        writer.writerow(line)

    outfile.close()


def _outputMacroLinks(network, macrolink_filepath, projection, encoding):
    outfile = getFileHandle(macrolink_filepath, encoding)
    writer = csv.writer(outfile)

    writer.writerow(['name', 'link_id', 'osm_way_id', 'from_node_id', 'to_node_id', 'dir_flag', 'length', 'lanes',
                     'free_speed', 'capacity', 'link_type_name', 'link_type', 'geometry','allowed_uses','from_biway',
                     'is_link', 'VDF_fftt1', 'VDF_cap1'])
    for link_id, link in network.link_dict.items():
        from_biway = 1 if link.from_bidirectional_way else 0
        is_link = 1 if link.is_link else 0
        if projection:
            geometry_ = wkt.dumps(link.geometry_xy, rounding_precision=og_settings.local_coord_precision)
        else:
            geometry_ = wkt.dumps(link.geometry, rounding_precision=og_settings.lonlat_coord_precision)
        line = [link.name, link.link_id, link.osm_way_id, link.from_node.node_id, link.to_node.node_id, link.dir_flag, link.length,
                link.lanes, link.free_speed, link.capacity, link.link_type_name, link.link_type, geometry_, ';'.join(link.allowed_uses) if link.allowed_uses else '',
                from_biway, is_link, link.VDF_fftt1, link.VDF_cap1]
        writer.writerow(line)

    outfile.close()


def outputMacroNet(network, output_folder, prefix, projection, encoding):
    macronet_folder = os.path.join(output_folder, 'macronet')
    if not os.path.isdir(macronet_folder): os.mkdir(macronet_folder)

    macronode_filepath = os.path.join(macronet_folder, f'{prefix}node.csv')
    _outputMacroNodes(network, macronode_filepath, projection, encoding)

    macrolink_filepath = os.path.join(macronet_folder, f'{prefix}link.csv')
    _outputMacroLinks(network, macrolink_filepath, projection, encoding)


