# Ben Stabley
# GEO242 Midterm
# 2023-05-20

from collections import namedtuple
import math

Point = namedtuple("Point", ["x", "y"])
"""
Represents a location in eucledean space using floats for
the x and y components.
"""


class City:
    """
    City represents a named place with a point location.
    """

    @staticmethod
    def parse_line(line: str) -> "City":
        """
        Parse an input line. Expected format is 'NAME X Y' where NAME
        is a string and X and Y are floats.

        parse_line() will raise an ValueError if the line is not in the correct
        format or if either X or Y cannot be parsed to floats. Although the normal
        format for NAME is to use underscores instead of spaces, this parse function
        will accept spaces in the city NAME.
        """
        line = line.strip()
        # this split will start from the right side and get 3 parts (2 splits).
        # it will use any whitespace as the delimeter.
        # thus, even if the city name as spaces in it (eg "New York" vs "New_York")
        # the line will be parsed correctly.
        parts = line.rsplit(maxsplit=2)
        if len(parts) != 3:
            raise ValueError("expected line in format 'NAME X Y'")

        name = parts[0].strip().replace("_", " ")
        x = float(parts[1].strip())  # allow parse error to be raised if x or y are invalid
        y = float(parts[2].strip())

        return City(name=name, location=Point(x, y))

    def __init__(self, name: str, location: Point):
        """Create a new city with name and location."""
        self.name = name
        self.location = location

    def dist_to(self, other: "City") -> float:
        """Calculate the euclidean distance from this city to the other city."""
        return math.dist(self.location, other.location)

    def __str__(self) -> str:
        """Get a pretty string representation of the city."""
        return f"{self.name} is at ({self.location.x:.1f}, {self.location.y:.1f})"

    def to_line(self) -> str:
        """
        Get back the original input line format of the city.

        Although the parse function accepts spaces in the city's name, this
        function will replace all spaces with underscores.
        """
        return f"{self.name.replace(' ', '_')} {self.location.x} {self.location.y}"

    def __eq__(self, other: "City") -> bool:
        """Two cities are equal if they have the same name and location."""
        return self.name == other.name and self.location == other.location
