class WMTLocations():
    """
    Service object used to find stops or stations (locations) - given a position, exact match or fuzzy match,
    will return the best matching stop. Subclassed and not called directly
    """
    def __init__(self, instance_name):
        self.database = WMTDatabase('%s.geodata.db' % instance_name)
        self.network = None
        self.returned_object = Location

    def find_closest(self, position, params):
        """
        Find the closest location to the (lat, long) position specified, querying the database with dictionary params, of the format
        { Column Name : value }. Returns an object of class returned_object, or None if none found nearby
        """
        # GPSes use WGS84 model of Globe, but Easting/Northing based on OSGB36, so convert to an easting/northing
        logging.debug("Position in WGS84 determined as lat/long: %s %s", position[0], position[1])
        easting, northing = convertWGS84toOSEastingNorthing(*position)
        logging.debug("Translated into OS Easting %s, Northing %s", easting, northing)

        # Do a funny bit of Pythagoras to work out closest stop. We can't find square root of a number in sqlite
        # but then again, we don't need to, the smallest square will do. Sort by this column in ascending order
        # and find the first row
        (where_statement, where_values) = self.database.make_where_statement('locations', params)
        query = """
                SELECT (location_easting - %d)*(location_easting - %d) + (location_northing - %d)*(location_northing - %d) AS dist_squared,
                      *
                FROM locations
                WHERE %s
                ORDER BY dist_squared
                LIMIT 1
                """ % (easting, easting, northing, northing, where_statement)
        row = self.database.get_row(query, where_values)
        if row:
            obj = self.returned_object(Distance=sqrt(row['dist_squared']), **row)
            logging.debug("Have found nearest location %s", obj)
            return obj
        else:
            logging.debug("No location found near %s, sorry", position)
            return None

    def find_fuzzy_match(self, stop_or_station_name, params):
        """
        Find the best fuzzy match to the query_string, querying the database with dictionary params, of the format
        { Column Name : value, }. Returns an object of class returned_object, or None if no fuzzy match found
        """
        if not stop_or_station_name or stop_or_station_name == "Unknown":
            return None
        # Try to get an exact match first against station names in database
        exact_params = params.copy()
        exact_params.update({'name': stop_or_station_name})
        exact_match = self.find_exact_match(exact_params)
        if exact_match:
            return exact_match

        # Users may not give exact details, so we try to match fuzzily
        (where_statement, where_values) = self.database.make_where_statement('locations', params)
        rows = self.database.get_rows("SELECT * FROM locations WHERE %s" % where_statement, where_values)
        possible_matches = [self.returned_object(**row) for row in rows]
        best_match = get_best_fuzzy_match(stop_or_station_name, possible_matches)
        if best_match:
            return best_match
        else:
            return None

    def find_exact_match(self, params):
        """
        Find the exact match for an item matching params. Returns an object of class returned_object, or None if no
        fuzzy match found
        """
        (where_statement, where_values) = self.database.make_where_statement('locations', params)
        row = self.database.get_row("SELECT * FROM locations WHERE %s LIMIT 1" % where_statement, where_values)
        if row:
            return self.returned_object(**row)
        else:
            return None