#!/usr/pkg/bin/perl

#
# Grabs the latest local weather conditions from the 
# National Weather Service (NWS).  Uses the decoded METAR reports.
#
# Need to give the 4-character METAR station code on the 
# Command Line. E.g.;
#
#           GrabWeather YSSY
#

$ReportDir  = '.wmWeatherReports';
#$WeatherSrc = 'ftp://weather.noaa.gov/data/observations/metar/decoded';
$WeatherSrc = 'http://weather.noaa.gov/pub/data/observations/metar/decoded';

use strict; 
use vars qw( $ReportDir $WeatherSrc );
use IO::File;

#
#  Change to users home directory. We used to dump into /tmp
#  but using home dir instead avoids multiple users interfering
#  with one another. (Yeah, we could "unique-ize" the filenames, but
#  this is easier for now...)
#
my $home = $ENV{HOME} || (getpwuid($<))[7];
chdir() || chdir($home) or die "chdir '$home' failed: $!";

unless(-e $ReportDir) {
  mkdir $ReportDir, 0755 or die "unable to mkdir '$ReportDir': $!";
}
chdir $ReportDir or die "chdir '$ReportDir' failed: $!";

my $StationID    = uc shift @ARGV or die "Usage: $0 <station-id>\n";
my $HTMLFileName = "$StationID.TXT";
my $URL          = "$WeatherSrc/$HTMLFileName";
my $DataFileName = "$StationID.dat";

# Is LWP installed?
eval { require LWP::UserAgent };
if ($@) {
  my $cmd = qq{wget --proxy=off --passive-ftp --tries=0 --quiet } .
            qq{--output-document=$home/$ReportDir/$HTMLFileName $URL};
  `$cmd` == 0 or die "unable to fetch weather: $?";
} else {
  $ENV{FTP_PASSIVE} = 1; # LWP uses Net::FTP internally.
  my $ua  = new LWP::UserAgent;
  my $req = new HTTP::Request( GET => $URL );
  my $rsp = $ua->request( $req );
  die $rsp->status_line unless $rsp->is_success;
  my $fh = new IO::File "> $home/$ReportDir/$HTMLFileName" 
    or die "unable to write '$home/$ReportDir/$HTMLFileName': $!";
  print $fh $rsp->content;
  close $fh or die "error closing '$home/$ReportDir/$HTMLFileName': $!";
}

#
# Parse HTML File. 
#

my %stats = (
  temp           => -99.0,
  chill          => -99.0,
  dew_point      => -99.0,
  pressure       => -99.0,
  humidity       => -99.0,
  universal_time => '99:99',
);

my $fh = new IO::File $HTMLFileName 
  or die "unable to read '$HTMLFileName': $!";

chomp($stats{station_info} = <$fh>);
chomp($stats{update_time}  = <$fh>);
while (<$fh>){
  chomp;
  $stats{sky_conditions} = $1, next if /Sky conditions: (.*)/;
  $stats{temp} = $1, next if /Temperature:\s*(\-{0,1}[0-9.]{1,}).*/;
  $stats{chill} = $1, next if /Windchill:\s*(\-{0,1}[0-9.]{1,}).*/;
  $stats{dew_point} = $1, next if /Dew Point:\s*(\-{0,1}[0-9.]{1,}).*/;
  $stats{pressure} = $1, next if /Pressure \(.*\):\s*([0-9.]{2,}).*/;
  $stats{humidity} = $1, next if /Relative Humidity:\s*(\d{1,})\%.*/;
  $stats{coded_metar} = $1, next if /ob: (.*)/;
}
close $fh or die "error closing '$HTMLFileName': $!";
    
#
#  Isolate the Wind groups out of the coded METAR report.
#  There may be two groups - the normal one and a variability set.
#
$stats{wind_group} = $stats{coded_metar};
$stats{wind_group} =~ s/ RMK\s.*$//;

$stats{var_flag} = 1 if $stats{wind_group} =~ /\d+(KT|MPS)\s\d+V\d+\s/;

if ($stats{wind_group} =~ /\s(\w{3})(?:(\d+)G)?(\d+)(KT|MPS)\s/) {
  @stats{qw( direction speed1 speed2 )} = ($1, $2, $3);
  if ($4 eq 'MPS') {
    $stats{speed1} *= 1.942 if defined $stats{speed1};
    $stats{speed2} *= 1.942; 
  } 
}

#
#  Get the Time out of the coded Metar Report.
#

if ($stats{coded_metar} =~ /$StationID \d+?(\d{2})(\d{2})Z/) {
  $stats{universal_time} = "$1:$2";
}

#
#  Write out the stuff we need to the Data File. This is the file that will
#  be read by GKrellWeather.
#
my $fh = new IO::File ">$DataFileName" 
  or die "unable to write '$DataFileName': $!";

print $fh
  map { "$stats{$_}\n" } 
    qw( station_info update_time sky_conditions universal_time
        temp dew_point chill pressure humidity );

if (not exists $stats{direction}) {
  print $fh "-99\n";
} elsif ($stats{direction} =~ /VRB/) {
  print $fh "99\n";
} elsif ($stats{var_flag}) {
  print $fh $stats{direction} * -1, "\n";
} else {
  print $fh $stats{direction} + 0, "\n";
}

if (not $stats{direction}) {
  print $fh "-99\n";
} elsif (defined $stats{speed1} and defined $stats{speed2}) {
  my $ave_speed = (($stats{speed1} + $stats{speed2})/2.0) * 1.15155;
  print $fh "-$ave_speed\n";
} else {
  print $fh $stats{speed2} * 1.15155, "\n";
}

close $fh or die "error closing '$DataFileName': $!";

