require 'rss/2.0'
require 'open-uri'

def get_forecast(loc, type)
  url = "http://newsrss.bbc.co.uk/weather/forecast/#{loc}/#{type}.xml"
  
  open(url) do |s|
    content = s.read
    return RSS::Parser.parse(content, false)
  end
end

def parse(str, re)
  str.match(re) or raise "failed to parse #{str}" 
end

def parse_latest(rss)
  info = {}
  title = parse(rss.channel.title, /Latest Observations for (.*),/)
  descr1 = parse(rss.items[0].description,
                 /Temperature: (-?\d+).*Wind Direction: (\w+).*Wind Speed: (\d+)/)
  descr2 = parse(rss.items[0].description,
                 /Humidity: (\d+).*Pressure: (\d+).*Visibility: (.*)/)
  { :where => title[1],
    :temp  => descr1[1],
    :wind  => descr1[3],
    :wdir  => descr1[2],
    :humid => descr2[1],
    :press => descr2[2],
    :vis   => descr2[3] }
end

def parse_3day(rss)
  rss.items.collect do |i|
    m = parse(i.title, /(\w+): ([\w\s]+), Max Temp: (-?\d+).*, Min Temp: (-?\d+)/)
    { :day   => m[1],
      :short => m[2],
      :max   => m[3],
      :min   => m[4] }
  end
end

def fmt_temp(val)
  if $units == 'f' then
    "#{(9 * val.to_i) / 5 + 32}°F"
  else
    "#{val}°C"
  end
end

top = 800

loc = $ARGV[0].to_i or raise "please specify location"
$units = $ARGV[1] || 'c'

raise "bad units #{$units}" unless $units == 'c' or $units == 'f'

days = parse_3day(get_forecast(loc, 'Next3DaysRSS'))
now = parse_latest(get_forecast(loc, 'ObservationsRSS'))

puts "${alignc}#{now[:where]}"
printf "${color2}Temperature: ${color1}%-7s", "#{fmt_temp now[:temp]}"
printf "${color2}Wind: ${color1}#{now[:wind]}mph #{now[:wdir]}\n"
printf "${color2}Humidity: ${color1}%-9s", "#{now[:humid]}%"
printf "${color2}Pressure: ${color1}#{now[:press]}mb\n"
printf "${color2}Visibility: ${color1}%-7s\n", now[:vis]
puts
days.each do |d| 
  printf("${color2}%-9s ${color1}%s${alignr}%s${color2}/${color1}%s\n",
         d[:day], d[:short], fmt_temp(d[:max]), fmt_temp(d[:min]))
end
