require 'net/http' module ATCTools class NameDiscoveryError < StandardError; end class HeadingDiscoveryError < StandardError; end class Airport # Airport's ICAO code. attr_accessor :code # Airport's full name. attr_writer :name # Airport's magnetic variance from true north. attr_accessor :variance # URI of the web page used for the last airport name lookup. attr_reader :name_uri # URI of the web page used for the last heading lookup. attr_reader :heading_uri # Params: # :code, :name, :variance def initialize(code = nil, **kvargs) @code = code || (kvargs.fetch :code, '') @name = kvargs.fetch :name, '' @variance = kvargs.fetch :variance, 17.0 # TODO: Detect this intelligently. end # Airport's full name. def name discover_name if @name.empty? @name end # Discover the airport's full name based # on ICAO code. def discover_name @name_uri = "http://www.airnav.com/airport/#{@code.to_s.downcase}" response = Net::HTTP.get URI name_uri l = response.scan %r{(?i:)(?:AirNav:\s*\w*\s*-\s*)?(.*)(?i:)} raise ATCTools::NameDiscoveryError, "Could not discover name for #{@code.to_s.upcase}" \ unless l.count > 0 @name = l.flatten.first end # Discover the airport's magnetic variance # based on ICAO code. def discover_variance end # Calculate the true heading to the specified airport. # Takes an ICAO code or Airport object. def true_heading_to(arrival) @heading_uri = "http://www6.landings.com/cgi-bin/nph-dist_apt?airport1=#{@code.downcase}&airport2=#{arrival.to_s.strip.downcase}" response = Net::HTTP.get URI heading_uri r = response.scan /(?:heading:)\s*([\d\.]+)\s+/ raise ATCTools::HeadingDiscoveryError, "Heading from #{@code.upcase} to #{arrival.to_s.upcase} not found." \ unless r.count > 0 true_hdg = r.flatten.first.to_f end # Calculate the true heading from the specified airport. # Takes an ICAO code or Airport object. def true_heading_from(departure) 360.0 - true_heading_to(departure) end # Calculate the magnetic heading to the specified airport. # Takes an ICAO code or Airport object. def magnetic_heading_to(arrival) true_to_magnetic true_heading_to(arrival) end # Calculate the magnetic heading from the specified airport. # Takes an ICAO code or Airport object. def magnetic_heading_from(departure) true_to_magnetic true_heading_from(departure) end # Convert a true heading to magnetic based on the airport's # magnetic variance. def true_to_magnetic(heading) heading - @variance end # Convert a magnetic heading to true based on the airport's # magnetic variance. def magnetic_to_true(heading) heading + @variance end # Print the Airport ICAO code. # Allows the object to act as a direct replacement for string input. def to_s @code.to_s.upcase end end end