module FakeRedis::GeoCommands

def do_georadius(set, center, radius, unit, args)

def do_georadius(set, center, radius, unit, args)
  points = set.points_within_radius(center, radius)
  options = georadius_options(args)
  if options[:asc]
    points.sort_by! { |p| p.distance_to(center) }
  elsif options[:desc]
    points.sort_by! { |p| -p.distance_to(center) }
  end
  points = points.take(options[:count]) if options[:count]
  extras = options[:extras]
  return points.map(&:name) if extras.empty?
  points.map do |point|
    member = [point.name]
    extras.each do |extra|
      case extra
      when "WITHCOORD"
        member << [point.lon.to_s, point.lat.to_s]
      when "WITHDIST"
        distance = point.distance_to(center)
        distance_in_units = distance / DISTANCE_UNITS[unit]
        member << distance_in_units.round(REDIS_DOUBLE_PRECISION).to_s
      when "WITHHASH"
        member << point.geohash(REDIS_GEOHASH_SIZE)
      end
    end
    member
  end
end

def geoadd(key, *members)

def geoadd(key, *members)
  raise_argument_error("geoadd") if members.empty? || members.size % 3 != 0
  set = (data[key] ||= GeoSet.new)
  prev_size = set.size
  members.each_slice(3) do |member|
    set.add(*member)
  end
  set.size - prev_size
end

def geodist(key, member1, member2, unit = "m")

def geodist(key, member1, member2, unit = "m")
  unit = unit.to_s
  raise_command_error("ERR unsupported unit provided. please use #{DISTANCE_UNITS.keys.join(', ')}") unless DISTANCE_UNITS.include?(unit)
  set = (data[key] || GeoSet.new)
  point1 = set.get(member1)
  point2 = set.get(member2)
  if point1 && point2
    distance = point1.distance_to(point2)
    distance_in_units = distance / DISTANCE_UNITS[unit]
    distance_in_units.round(REDIS_DOUBLE_PRECISION).to_s
  end
end

def geohash(key, member)

def geohash(key, member)
  members = Array(member)
  raise_argument_error("geohash") if members.empty?
  set = (data[key] || GeoSet.new)
  members.map do |member|
    point = set.get(member)
    point.geohash(REDIS_GEOHASH_SIZE) if point
  end
end

def geopos(key, member)

def geopos(key, member)
  return nil unless data[key]
  members = Array(member)
  set = (data[key] || GeoSet.new)
  members.map do |member|
    point = set.get(member)
    [point.lon.to_s, point.lat.to_s] if point
  end
end

def georadius(*args)

def georadius(*args)
  args = args.dup
  raise_argument_error("georadius") if args.size < 5
  key, lon, lat, radius, unit, *rest = args
  raise_argument_error("georadius") unless DISTANCE_UNITS.has_key?(unit)
  radius *= DISTANCE_UNITS[unit]
  set = (data[key] || GeoSet.new)
  center = GeoSet::Point.new(lon, lat, nil)
  do_georadius(set, center, radius, unit, rest)
end

def georadius_options(args)

def georadius_options(args)
  options = {}
  args = args.map { |arg| arg.to_s.upcase }
  if idx = args.index("COUNT")
    options[:count] = Integer(args[idx + 1])
  end
  options[:asc]  = true if args.include?("ASC")
  options[:desc] = true if args.include?("DESC")
  extras = args & ["WITHCOORD", "WITHDIST", "WITHHASH"]
  options[:extras] = extras
  options
end

def georadiusbymember(*args)

def georadiusbymember(*args)
  args = args.dup
  raise_argument_error("georadiusbymember") if args.size < 4
  key, member, radius, unit, *_ = args
  raise_argument_error("georadiusbymember") unless DISTANCE_UNITS.has_key?(unit)
  radius *= DISTANCE_UNITS[unit]
  set = (data[key] || GeoSet.new)
  center = set.get(member)
  raise_command_error("ERR could not decode requested zset member") unless center
  do_georadius(set, center, radius, unit, args)
end