module Geokit
  module Geocoders
    # MapQuest geocoder implementation.  Requires the Geokit::Geocoders::MapQuestGeocoder:key
    # variable to contain a MapQuest API key.  Conforms to the interface set by the Geocoder class.
    class MapQuestGeocoder < Geocoder
      config :key
      self.secure = true

      private

      # Template method which does the reverse-geocode lookup.
      def self.do_reverse_geocode(latlng)
        latlng = LatLng.normalize(latlng)
        url = "#{protocol}://www.mapquestapi.com/geocoding/v1/reverse?key=#{key}&location=#{latlng.lat},#{latlng.lng}"
        process :json, url
      end

      # Template method which does the geocode lookup.
      def self.do_geocode(address, _=nil)
        address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
        url = "#{protocol}://www.mapquestapi.com/geocoding/v1/address?key=#{key}&location=#{Geokit::Inflector.url_escape(address_str)}"
        process :json, url
      end

      def self.parse_json(results)
        return GeoLoc.new unless results['info']['statuscode'] == 0
        loc = nil
        results['results'].each do |result|
          result['locations'].each do |location|
            extracted_geoloc = extract_geoloc(location)
            if loc.nil?
              loc = extracted_geoloc
            else
              loc.all.push(extracted_geoloc)
            end
          end
        end
        loc
      end

      def self.extract_geoloc(result_json)
        loc = new_loc
        loc.lat = result_json['latLng']['lat']
        loc.lng = result_json['latLng']['lng']
        set_address_components(result_json, loc)
        set_precision(result_json, loc)
        loc.success = true
        loc
      end

      def self.set_address_components(result_json, loc)
        loc.country_code   = result_json['adminArea1']
        loc.street_address = result_json['street'].to_s.empty? ? nil : result_json['street']
        loc.city           = result_json['adminArea5']
        loc.state          = result_json['adminArea3']
        loc.zip            = result_json['postalCode']
      end

      def self.set_precision(result_json, loc)
        loc.precision = result_json['geocodeQuality']
        loc.accuracy = %w(unknown country state state city zip zip+4 street address building).index(loc.precision)
      end
    end
  end
end
