#!/usr/local/bin/perl

# tell us the weather
# weather.pl v2011061501
# Copyright 2010-2011 Jeremy Kister
# Released under Perl's Artistic License


# in /etc/asterisk/extensions.conf:
# [weather]
# exten => s,1,Answer
# exten => s,n,AGI(weather.pl,90210);
# exten => s,n,Hangup()

## Note: you may ommit the zip code argument, and the AGI will
## ask you for one.


#sed s/^#// << __EOSQL__ | sqlite3 /var/sql/weather.db
#CREATE TABLE current (
# id INTEGER PRIMARY KEY NOT NULL,
# condition VARCHAR(255),
# temp_f TINYINT NOT NULL,
# wind_condition VARCHAR(255),
# humidity VARCHAR(255),
# zip CHAR(5) NOT NULL,
# location VARCHAR(255),
# time INT NOT NULL
#);
#
#CREATE TABLE forecast (
# id INTEGER PRIMARY KEY NOT NULL,
# condition VARCHAR(255),
# high TINYINT NOT NULL,
# low TINYINT NOT NULL,
# day_of_week VARCHAR(10),
# zip CHAR(5) NOT NULL,
# time INT NOT NULL
#);
#
#create index current01  on current(time);
#create index current02  on current(zip);
#create index forecast01 on forecast(time);
#create index forecast02 on current(zip);
#__EOSQL__


use strict;
use DBI;
use LWP::UserAgent;
use XML::Simple;
use Asterisk::AGI;


my $agi = Asterisk::AGI->new();

my $zip = $ARGV[0];
while($zip !~ /^\d{5}$/){
	swift( "Enter zip code,5000,5" );
	$zip = $agi->get_variable('SWIFT_DTMF');
}

my ($dbun,$dbpw);
my $dsn = 'DBI:SQLite:dbname=/var/sql/weather.db';
my $dbh = DBI->connect($dsn, $dbun, $dbpw, {RaiseError => 1});
my %f;

my $hourago = ($^T - 3600);

my $sql = 'SELECT condition,temp_f,wind_condition,humidity,location' .
          '  FROM current' .
          " WHERE time > $hourago" .
          '   AND zip = ' . $dbh->quote($zip);
my $sth = $dbh->prepare($sql);
$sth->execute;
my $c = $sth->fetchrow_hashref;
my $location = $c->{location};

$sql = '   SELECT condition,high,low,day_of_week ' .
       '     FROM forecast ' .
       "    WHERE time > $hourago " .
       '      AND zip = ' . $dbh->quote($zip) .
       ' ORDER BY id';
$sth = $dbh->prepare($sql);
$sth->execute;
my $i = 0;
while(my $row=$sth->fetchrow_hashref){
	foreach my $field (qw/condition high low day_of_week/){
		$f{$i}{$field} = $row->{$field};
	}
	$i++;
}

unless( $c->{condition} && $f{0}{condition} ){
	my $ua = LWP::UserAgent->new;
	$ua->timeout(10);
	
	my $response = $ua->get("http://www.google.com/ig/api?weather=${zip}&hl=en");
	unless($response->is_success){
		die $response->status_line;
	}
	
	my $xs = XML::Simple->new;
	my $href = $xs->XMLin($response->decoded_content);
	$location = $href->{weather}{forecast_information}{city}{data};
	
	for my $table (qw/current forecast/){
		my $sql = "DELETE FROM $table" .
                          ' WHERE zip = ' . $dbh->quote($zip);
		my $sth = $dbh->prepare($sql);
		$sth->execute;
	}

	my $sql = 'INSERT INTO current (temp_f,condition,wind_condition,humidity,zip,location,time) VALUES (';
	foreach my $key (qw/temp_f condition wind_condition humidity/){
		$c->{$key} = $href->{weather}{current_conditions}{$key}{data};
		$sql .= $dbh->quote($c->{$key}) . ',';
	}
	$sql .= $dbh->quote($zip)      . ',' .
                $dbh->quote($location) . ',' .
                time() . ')';
	$sth = $dbh->prepare($sql);
	$sth->execute;
	
	foreach my $dow (0..3){
		my $sql = 'INSERT INTO forecast (high,low,day_of_week,condition,zip,time) VALUES (';
		foreach my $key (qw/high low day_of_week condition/){
			$f{$dow}{$key} = $href->{weather}{forecast_conditions}[$dow]{$key}{data};
			$sql .= $dbh->quote($f{$dow}{$key}) . ',';
		}
		$sql .= $dbh->quote($zip) . ',' . time() . ')';
		my $sth = $dbh->prepare($sql);
		$sth->execute;
	}
	
}
my %eng_dir = (N => 'North', E => 'East', S => 'South', W => 'West');

my %days = (Sun => 'Sunday', Mon => 'Monday', Tue => 'Tuesday', Wed => 'Wednesday',
	    Thu => 'Thursday', Fri => 'Friday', Sat => 'Saturday' );

my ($dirs) = $c->{wind_condition} =~ /Wind: ([NESW]{1,2})/;
my $eng;
foreach my $dir (split //, $dirs){
	$eng .= "$eng_dir{$dir} ";
}
chop($eng); # just because - trailing space.
$c->{wind_condition} =~ s/Wind: $dirs/Wind: $eng/;

unless($ARGV[0]){
	$location =~ /(\S+) ([A-Z])([A-Z])$/;
	$location = "$1 $2 $3";

	swift( "Forecast for $location." );
}

# condition could be: showers, rain, cloudy, mostly cloudy
my $text = "It is currently $c->{temp_f} degrees and $c->{condition} <break time='500ms' />" .
           " $c->{wind_condition} and $c->{humidity}. ";

foreach my $dow (sort { $a <=> $b } keys %f){
	$text .= "$days{$f{$dow}{day_of_week}}: $f{$dow}{condition} " .
	         "with a high of $f{$dow}{high} <break time='45ms' /> and a low of $f{$dow}{low} " .
             "<break time='500ms' />.  ";
}

swift( $text );


sub swift {
	my $msg = join(' ', @_);

	$agi->exec('Swift', $msg);
}
