# encoding: UTF-8
module Graticule

  # A geographic location
  class Location
    attr_accessor :latitude, :longitude, :street, :locality, :region, :postal_code, :country, :precision, :warning
    alias_method :city, :locality
    alias_method :state, :region
    alias_method :zip, :postal_code

    def initialize(attrs = {})
      attrs.each do |key,value|
        self.send("#{key}=", value.respond_to?(:force_encoding) ? value.force_encoding('UTF-8') : value)
      end
      self.precision ||= :unknown
    end

    def precision=(precision)
      @precision = Precision.new(precision.to_s)
    end

    def attributes
      [:latitude, :longitude, :street, :locality, :region, :postal_code, :country, :precision].inject({}) do |result,attr|
        result[attr] = self.send(attr) unless self.send(attr).blank?
        result
      end
    end

    def blank?
      attributes.except(:precision).empty?
    end

    # Returns an Array with latitude and longitude.
    def coordinates
      [latitude, longitude]
    end

    def ==(other)
      other.respond_to?(:attributes) ? attributes == other.attributes : false
    end

    # Calculate the distance to another location.  See the various Distance formulas
    # for more information
    def distance_to(destination, options = {})
      options = {:formula => :haversine, :units => :miles}.merge(options)
      "Graticule::Distance::#{options[:formula].to_s.titleize}".constantize.distance(self, destination, options[:units])
    end

    # Where would I be if I dug through the center of the earth?
    def antipode
      Location.new :latitude => -latitude, :longitude => longitude + (longitude >= 0 ? -180 : 180)
    end
    alias_method :antipodal_location, :antipode

    def to_s(options = {})
      options = {:coordinates => false, :country => true}.merge(options)
      result = ""
      result << "#{street}\n" if street
      result << [locality, [region, postal_code].compact.join(" ")].compact.join(", ")
      result << " #{country}" if options[:country] && country
      result << "\nlatitude: #{latitude}, longitude: #{longitude}" if options[:coordinates] && [latitude, longitude].any?
      result
    end

  end
end
