from CSAir_json import * from CSAir_helpers import * import webbrowser import math from flask import Markup def list_locations(graph): """ Prints all of the cities stored in the graph. :param graph: the directed graph """ cities = graph.get_nodes() for city_node in cities: city_node.get_object().brief_print() def lookup(graph, code): """ Prints data for a specific city. :param graph: the directed graph :param code: the airport identifier for the city :return: True if the city was found, False otherwise """ city_node = graph.find_node(code) if city_node is None: return "Location, " + code + ", not found.\n" else: ret_str = city_node.get_object().get_info() ret_str += "\nRoutes departing from " + code + ":\n" edges = graph.get_edges_for_node(city_node) for edge in edges: dest_node = edge.get_destination() ret_str += code + " to " + Markup("" + str(dest_node) + "") \ + ", distance: " + edge + Markup(' ') + '\n' if len(edges) == 0: ret_str += "No routes." return ret_str def generate_map_url(graph): """ Returns a url to display a map at gcmap.com :param graph: the directed graph :return: string containing the url """ edges = graph.get_edges() url_string = "http://www.gcmap.com/map?P=" for edge in edges: url_string += (edge.get_source() + "-" + edge.get_destination() + "%0D%0A") return url_string + "&MS=wls&MR=1800&MX=720x360&PM=*" def show_map(url_string): """ Launches the default web browser to the specified url. :param url_string: a string containing a url """ print(url_string) webbrowser.open(url_string) def print_longest(graph): """ Prints the longest flight path :param graph: the directed graph """ edges = graph.get_edges() longest_edge = 0 longest_int = 0 for edge in edges: if int(edge) > longest_int: longest_edge = edge longest_int = int(edge) return "Longest flight: " + longest_edge.get_source() + " to " + longest_edge.get_destination() \ + ". " + longest_edge + "km" def print_shortest(graph): """ Prints the shortest flight path :param graph: the directed graph """ edges = graph.get_edges() shortest_edge = 0 shortest_int = 0 for edge in edges: if shortest_int == 0 or int(edge) < shortest_int: shortest_edge = edge shortest_int = int(edge) return "Shortest flight: " + shortest_edge.get_source() + " to " + shortest_edge.get_destination() \ + ". " + shortest_edge + "km" def print_average(graph): """ Prints the average size of all routes and the total number of routes :param graph: the directed graph """ edges = graph.get_edges() total = "Total routes: " + str(len(edges)) + "\n" total_distance = 0 for edge in edges: total_distance += int(edge) average = total_distance/len(edges) return total + "Average distance across all routes: " + str(math.floor(average)) + "km" def print_smallest_city(graph): """ Prints the smallest city :param graph: the directed graph """ nodes = graph.get_nodes() smallest_pop = 0 for node in nodes: node_pop = node.get_object().population if smallest_pop == 0 or node_pop < smallest_pop: smallest_city = node smallest_pop = node_pop ret_str = "Smallest city: " + smallest_city.get_object().get_brief() ret_str += "Population: " + str(smallest_pop) return ret_str def print_largest_city(graph): """ Prints the largest city :param graph: the directed graph """ nodes = graph.get_nodes() largest_pop = 0 for node in nodes: node_pop = node.get_object().population if node_pop > largest_pop: largest_city = node largest_pop = node_pop ret_str = "Largest city: " + largest_city.get_object().get_brief() ret_str += "Population: " + str(largest_pop) return ret_str def print_average_city(graph): """ Prints the average size of all cities and the total number of cities :param graph: the directed graph """ nodes = graph.get_nodes() ret_str = "Total cities: " + str(len(nodes)) + "\n" total_pop = 0 for node in nodes: node_pop = node.get_object().population total_pop += node_pop average = total_pop/len(nodes) return ret_str + "Average city size: " + str(math.floor(average)) def print_continents(graph): """ Prints the continents and cities within them :param graph: the directed graph """ nodes = graph.get_nodes() continents = [] # continents is a list of continent names. cities = [] # cities[i] is a list of cities in continent i for node in nodes: city = node.get_object() node_cont = city.continent if node_cont not in continents: continents.append(node_cont) cities.append([]) for i, _ in enumerate(continents): if continents[i] == node_cont: cities[i].append(city) ret_str = "" for i, _ in enumerate(continents): ret_str += "\nCities in " + continents[i] + ":\n" for city in cities[i]: ret_str += city.get_brief() return ret_str def print_hubs(graph): """ Prints the cities ordered from largest number of connections to smallest :param graph: the directed graph """ nodes = graph.get_nodes() num_edges = [] for node in nodes: edges = graph.get_edges_for_node(node) num_edges.append(len(edges)) both = zip(num_edges, nodes) # zip both lists into a tuple both = sorted(both)[::-1] # sort and reverse the tuple ret_str = "" for pair in both: city = pair[1].get_object() ret_str += str(pair[0]) + " connections from: " + city.get_brief() return ret_str def add_city(graph): """ Prompts the user to add a new city to the graph. :return: True on success, false on failure. """ print("Enter the new city's information:") code = input("Code: ").rstrip('\n') if code in graph.get_nodes(): print("City already exists, can not add. Perhaps you meant to edit the city?") return False use_api = input("Do you want to look up this city using the Wunderground API? (y/n)") if use_api == "y": return json_api_request(graph, code) else: name = input("Name: ").rstrip('\n') country = input("Country: ").rstrip('\n') continent = input("Continent: ").rstrip('\n') timezone = input("Timezone: ").rstrip('\n') latitude = input("Latitude: ").rstrip('\n') longitude = input("Longitude: ").rstrip('\n') population = input("Population: ").rstrip('\n') region = input("Region: ").rstrip('\n') add_city_helper(graph, code, name, country, continent, timezone, latitude, longitude, population, region) return True def add_route(graph): """ Prompts the user to add a new route. """ print("Enter the new route's information:") source = input("Source: ").rstrip('\n') dest = input("Destination: ").rstrip('\n') distance = input("Distance: ").rstrip('\n') direction = input("Add the route in both directions? (y/n): ").rstrip('\n') add_route_helper(graph, source, dest, distance, direction) def remove_city(graph): """ Prompts the user to remove a city. """ print("Enter the code of the city to remove:") code = input("Code: ").rstrip('\n') if graph.remove_node(code): print("City removed.") else: print("Unable to remove city. A city with the specified code does not exist.") def remove_route(graph): """ Prompts the user to remove a route. """ print("Enter the source and destination codes for the route to remove:") source = input("Source: ").rstrip('\n') dest = input("Destination: ").rstrip('\n') direction = input("Remove the route in both directions? (y/n): ").rstrip('\n') remove_route_helper(graph, source, dest, direction) def edit_city(graph, code): """ Prompts the user to edit a city. :param code: The city to edit :return: True if edited, false otherwise. """ node = graph.find_node(code) if node is None: print("City not found, can not edit.") return False city = node.get_object() print("Editing " + code + "'s information:" "\nThe current information will be displayed, then you can enter new information:" "\nTo keep the current information, leave the section blank.") code = update_data("Code", city.code) name = update_data("Name", city.name) country = update_data("Country", city.country) continent = update_data("Continent", city.continent) timezone = update_data("Timezone", str(city.timezone)) latitude = update_data("Latitude", str(city.latitude)) longitude = update_data("Longitude", str(city.longitude)) population = update_data("Population", str(city.population)) region = update_data("Region", str(city.region)) graph.remove_node(node) if not add_city_helper(graph, code, name, country, continent, timezone, latitude, longitude, population, region): #if modifying the city failed, add the old one back to the graph. graph.add_node(node) return False #edit current routes to match new information! update_routes(graph, code, node) return True def route_info(graph): """ Prompts the user to enter a list of cities, then will display cost, time, and distance for the route. :return: False on error, True otherwise. """ try: num_cities = int(input("Total number of cities in the route: ")) except ValueError: print("Error: Number of cities must be an integer.") return False if num_cities <= 0: print("Error: The number of cities in the route must be greater than 0.") return False nodes = graph.get_nodes() print("Enter the city codes for the route. Type cancel to return back to the main prompt.") route = [] for i in range(num_cities): code = input(":") if code == "cancel": return True elif code not in nodes: print("Error: " + code + " is not a city in our current data.") return False route.append(code) return route_helper(graph, route) def route_shortest(graph): """ Uses Dijkstra's algorithm to determine the shortest route between souce city and destination city. :return: False on error, true otherwise """ print("Enter the city codes for the route.") source = input("Source city: ") dest = input("Destination city: ") route = graph.dijkstra(source, dest) if route is None: return False return route_helper(graph, route)