require 'geocoder' require 'retryable'

Geocoder.configure(

lookup: :google,
timeout: 10,
api_key: GOOGLE_API_KEY

)

# raise on geocoding errors such as query limit exceeded Geocoder.configure(always_raise: :all) # Try to geocode a given query, on exceptions it retries up to 3 times then gives up. # @param [String] query string to geocode # @return [Hash] first valid result or nil def geocode(query, params)

Retryable.retryable(tries: 3, sleep: ->(n) { 2**n }) do
  Geocoder.search(query, params: params).first
end

rescue => e

warn "Attempts exceeded for query #{query}, last error was #{e.message}"
nil

end

def load_country_yaml(alpha2)

YAML.load_file(File.join(ISO3166_ROOT_PATH, 'lib', 'countries', 'data', 'countries', "#{alpha2}.yaml"))

end

def save_country_yaml(alpha2, data)

File.open(File.join(ISO3166_ROOT_PATH, 'lib', 'countries', 'data', 'countries', "#{alpha2}.yaml"), 'w+') { |f| f.write data.to_yaml }

end

def country_codes

@country_codes ||= Dir['lib/countries/data/countries/*.yaml'].map { |x| File.basename(x, File.extname(x)) }.uniq

end

namespace :geocode do

desc 'Retrieve and store countries coordinates'
task :fetch_countries do
  require 'countries'
  # Iterate over countries
  ISO3166::Country.all.each do |country|
    code = country.alpha2
    # Load unmutated yaml file.
    data = load_country_yaml(country.alpha2)

    next unless (result = geocode(country.name, {region: country.alpha2}))
    puts "WARNING:: Geocoder returned something that was not a country for #{country.alpha2}" unless result.types.include?('country')
    geometry = result.geometry

    # Extract center point data
    if geometry['location']
      data[code]['geo']['latitude'] = geometry['location']['lat']
      data[code]['geo']['longitude'] = geometry['location']['lng']
    end

    # Extract bounding box data
    next unless geometry['bounds']
    data[code]['geo']['bounds'] = geometry['bounds']
    data[code]['geo']['min_latitude'] = geometry['bounds']['southwest']['lat']
    data[code]['geo']['min_longitude'] = geometry['bounds']['southwest']['lng']
    data[code]['geo']['max_latitude'] = geometry['bounds']['northeast']['lat']
    data[code]['geo']['max_longitude'] = geometry['bounds']['northeast']['lng']

    # Persist
    save_country_yaml(code, data)
  end
end

desc 'Retrieve and store subdivisions coordinates'
task :fetch_subdivisions do
  require_relative '../../countries'
  # Iterate all countries with subdivisions
  ISO3166::Country.all.select(&:subdivisions?).each do |c|
    # Iterate subdivisions
    state_data = c.subdivisions.dup
    state_data.reject { |_, data| data['geo'] }.each do |code, data|
      location = "#{c.alpha2}-#{code}"

      next unless (result = geocode(location, {region: c.alpha2}))

      geometry = result.geometry
      if geometry['location']
        state_data[code]['geo'] ||= {}
        state_data[code]['geo']['latitude'] = geometry['location']['lat']
        state_data[code]['geo']['longitude'] = geometry['location']['lng']
      end
      next unless geometry['bounds']
      state_data[code]['geo']['min_latitude'] = geometry['bounds']['southwest']['lat']
      state_data[code]['geo']['min_longitude'] = geometry['bounds']['southwest']['lng']
      state_data[code]['geo']['max_latitude'] = geometry['bounds']['northeast']['lat']
      state_data[code]['geo']['max_longitude'] = geometry['bounds']['northeast']['lng']
    end
    # Write updated YAML for current country
    File.open(File.join(ISO3166_ROOT_PATH, 'lib', 'countries', 'data', 'subdivisions', "#{c.alpha2}.yaml"), 'w+') { |f| f.write state_data.to_yaml }
  end
end

end