async def main(args):
    director = Director()
    log = get_logger("Main")

    if args.targets is not None and len(args.targets) > 0:
        await set_nodes(director, args.targets)

    if args.type == "location":
        await set_locations(director, args.city_num)
    elif args.type == "weather_agent":
        await set_weather_agents(director)
    elif args.type == "location_and_connection":
        await set_locations_and_connections(director, args.city_num)
    elif args.type == "json_config":
        if len(args.config_file) == 0:
            print("json_config requires a json config file!")
            return
        await config_from_json(director, args.config_file)
    elif args.type == "bootstrap":
        with open(args.bootstrap_config, "r") as f:
            config = json.load(f)
        config = update_config_from_state(config, log)
        b = Bootstrap(config["bootstrap"])
        config["bootstrap"] = b.update_config()
        update_state(config, log)
        await from_bootstrap(director, b, config)
    else:
        print("Command type {} not supported!".format(args.type))

    await director.close_all()

    await director.wait()
async def set_locations_and_connections(director: Director, city_num: int):
    grid = EnglandGrid.EnglandGrid(city_num)
    grid.load()

    core_names = get_core_names(grid)

    peers = {}
    addresses = {}
    print(director.addresses)
    for key, entity in grid.entities.items():
        if entity.kind != "CITY":
            continue
        name = next(core_names)
        a = director.get_address(name)
        if len(a) == 0:
            continue
        core_name = name + "-core"
        print("SET LOCATION {}@{}:{} NODE TO {}".format(
            core_name, a[0], a[1], entity.name))
        addresses[core_name] = a
        peers[name] = [
            link[0].name for link in entity.links if link[1] == "GND"
        ]
        await director.set_location(name, core_name.encode("utf-8"),
                                    (entity.coords[1], entity.coords[0])
                                    )  #lon, lat
    for key in peers:
        targets = [("Search" + str(addresses[peer][1] - 40000),
                    addresses[peer][0], addresses[peer][1] - 20000)
                   for peer in peers[key] if peer in addresses]
        print("ADD PEERS for search {}: ".format(key), targets)
        await director.add_peers(key, targets)
async def set_weather_agents(director: Director):
    names = director.get_node_names()
    tasks = []
    core_names = get_core_names()
    for name in names:
        host, port = director.get_address(name)
        if host.find("oef_node") != -1:
            i = int(host.replace("oef_node", ""))
        else:
            i = int(port)-20000
        core_name = next(core_names)+"-core"
        print("SET WEATHER AGENT FOR: ", name, "; core_name: ", core_name)
        task = asyncio.create_task(director.send(name, "blk_update",
                                                 create_weather_agent_service(10000+i, core_name)))
        tasks.append(task)
    for task in tasks:
        await task
async def main(args):
    configure()
    director = Director()

    await set_nodes(director, args.port_start, args.port_end)

    await set_weather_agents(director)

    await director.close_all()

    await director.wait()
async def set_locations(director: Director):
    grid = EnglandGrid.EnglandGrid()
    grid.load()

    i = 0
    names = director.get_node_names()
    for key, entity in grid.entities.items():
        core_name = (entity.name + "-core").encode("UTF-8")
        await director.set_location(names[i], core_name,
                                    (entity.coords[1], entity.coords[0])
                                    )  #lon, lat
        i += 1
        if i >= len(names):
            break
async def config_from_json(director: Director, json_config: str):
    with open(json_config, "r") as f:
        config = json.load(f)
    internal_hosts = config["internal_hosts"]
    config = config["nodes"]
    print(config)

    uri_map = {}

    for c in config:
        host, port = c["director_uri"].split(":")
        name = c["name"]
        await set_node(director, host, port, name)
        coords = c["location"]
        core_name = name + "-core"
        print("SET LOCATION {}@{} NODE TO {}".format(core_name, c["core_uri"],
                                                     coords))
        await director.set_location(name, core_name.encode("utf-8"),
                                    tuple(coords))
        uri_map[name] = c["uri"]

    for c in config:
        peers = [(peer, *uri_map[peer].split(":")) for peer in c["peers"]
                 if peer in uri_map]
        peers = [(d[0] + "-search",
                  d[1] if d[0] not in internal_hosts else internal_hosts[d[0]],
                  d[2]) for d in peers]
        print("ADD PEERS for search {}: ".format(c["name"]), peers)
        await director.add_peers(c["name"], peers)

    await director.reset()

    tasks = []
    for c in config:
        host, port = c["uri"].split(":")
        name = c["name"]
        core_name = name + "-core"
        await set_node(director, host, port, c["name"])
        core_host, core_port = c["core_uri"].split(":")
        print("SET WEATHER AGENT FOR: ", name, "; core_name: ", core_name,
              "; address: {}:{}".format(core_host, core_port))
        task = asyncio.create_task(
            director.send(
                name, "blk_update",
                create_weather_agent_service(int(core_port), core_name,
                                             core_host)))
        tasks.append(task)
    for task in tasks:
        await task
async def set_locations(director: Director, city_num: int):
    grid = EnglandGrid.EnglandGrid(city_num)
    grid.load()
    core_names = get_core_names(grid)
    i = 0
    names = director.get_node_names()
    for key, entity in grid.entities.items():
        if entity.kind != "CITY":
            continue
        print("SET LOCATION {} NODE TO {}".format(names[i], entity.name))
        core_name = next(core_names)+"-core"
        await director.set_location(names[i], core_name.encode("UTF-8"), (entity.coords[1], entity.coords[0])) #lon, lat
        i += 1
        if i >= len(names):
            break
async def main(args):
    director = Director()

    if args.targets is not None and len(args.targets) > 0:
        await set_nodes(director, args.targets)

    if args.type == "location":
        await set_locations(director, args.city_num)
    elif args.type == "weather_agent":
        await set_weather_agents(director)
    elif args.type == "location_and_connection":
        await set_locations_and_connections(director, args.city_num)
    elif args.type == "json_config":
        if len(args.config_file) == 0:
            print("json_config requires a json config file!")
            return
        await config_from_json(director, args.config_file)
    else:
        print("Command type {} not supported!".format(args.type))

    await director.close_all()

    await director.wait()
async def from_bootstrap(director: Director, b: Bootstrap, config: dict):
    log = get_logger("BootstrapDirector")
    result = b.run_nodelist()
    oef_nodes = {}
    for binfo in result:
        if not binfo["last_seen"]:
            log.info("Skipping node ({}@{}:{}) because last_seen is null: {}".
                     format(binfo["public_key"], binfo["host"], binfo["port"],
                            json.dumps(binfo, indent=2)))
            continue
        if abs(time.time() - time_parser.parse(binfo["last_seen"]).timestamp()
               ) > config["last_seen_threshold_in_sec"]:
            log.info(
                "Skipping node ({}@{}:{}) because last_time was too long ago ({} s time threshold): {}"
                .format(config["last_seen_threshold_in_sec"],
                        binfo["public_key"], binfo["host"], binfo["port"],
                        json.dumps(binfo, indent=2)))
            continue
        await director.add_node(binfo["host"], binfo["port"])
        info = await director.get_info(
            director.name_from_address(binfo["host"], binfo["port"]))
        city = info.search_key.replace("-search", "")
        if binfo["host"] != info.host:
            log.info(
                "Host got as response from director info endpoint is different. Called: {}, got: {}"
                .format(binfo["host"], info.host))
        oef_nodes[city] = {
            "search_key": info.search_key,
            "core_key": info.core_key,
            "host": binfo["host"],
            "search_port": info.search_port,
            "core_port": info.core_port,
            "director_port": binfo["port"],
            "original_key": info.search_key
        }
    log.info("Got search nodes: {}".format(json.dumps(oef_nodes, indent=2)))
    map_data = get_map_data(len(oef_nodes))
    log.info("Map Data: {}".format(map_data))
    name_map = config["name_map"]
    oef_nodes_with_city_keys = {}
    for key, info in oef_nodes.items():
        right_key = key
        try:
            location, peer_list = map_data[right_key]
        except KeyError:
            try:
                right_key = name_map[info["original_key"]]
                log.info(
                    "Key %s not a valid city name! Key lookup in config resulted with "
                    "the following city: %s -> %s", key, info["original_key"],
                    right_key)
                location, peer_list = map_data[right_key]
            except KeyError:
                log.error(
                    "Key %s not a valid city name! Key lookup failed in name_map (set in config): %s!"
                    " Skipping node...", key, info["original_key"])
                continue
        dname = director.name_from_address(info['host'], info['director_port'])
        await director.set_location(dname, info["core_key"].encode("UTF-8"),
                                    location)
        oef_nodes_with_city_keys[right_key] = info
        oef_nodes_with_city_keys[right_key]["peer_list"] = peer_list
        oef_nodes_with_city_keys[right_key]["dname"] = dname
    for key, info in oef_nodes_with_city_keys.items():
        peers = [(inf["search_key"], inf["host"], inf["search_port"])
                 for inf in map(lambda name: oef_nodes_with_city_keys[name],
                                info["peer_list"])]
        await director.add_peers(info["dname"], peers)

    await director.close_all()
    await director.wait()
async def set_weather_agents(director: Director):
    i = 0
    names = director.get_node_names()
    for name in names:
        await director.send(name, "blk_update", create_blk_update(3333+i))
        i += 1