#!/usr/bin/perl
use Image::Magick;
use LWP::Simple;
use LWP::UserAgent;

my $period = 600;    # how many seconds between images
my $timeafter = 60;  # how many seconds after the start of the new period to start looking for a new image 
my $retry_period = 30;  # how many seconds between retries to find a new image
my $retry_max = 16;     # maximum number of retries before giving up
my $img_mod_time_early = 60;   # number of seconds the image mod time can be before the 
                               # start of the period to be considered acceptable
my $img_mod_time_late = 420;   # number of seconds the image mod time can be after the 
                               # start of the period to be considered acceptable
my $animation_destination = '/var/www/pics/radar_anim.gif';  # where to copy the animation to
my $archive_all_images = 1;    # if set to 1 then all images are kept in nice directories
                               # if set to 0 then only the necessary images are kept and those are left in cwd
my $animation_size = 25;       # number of images in the animation
my $time_offset = 0;           # number of seconds to add to the time() function to match wundergrounds time
my $old_imagemagick = 0;       # old versions of image magick "composite" function works with negative numbers
                               # slightly differently than new versions.  Try setting this to 1 if the images 
                               # aren't lining up right 

my $curtime = time() + $time_offset;
my $nexttime = int($curtime / $period) * $period + $timeafter;
if ($curtime < $nexttime) {
    sleep($nexttime - $curtime);
}

while(1) {

    create_image($nexttime - $timeafter);
    create_animation($nexttime - $timeafter - $period * ($animation_size - 1), $animation_size);
    unless ($archive_all_images) {
	remove_image($nexttime - $timeafter - $period * ($animation_size - 1));
    }
	

    $nexttime += $period;
    $curtime = time() + time_offset;
    print "current time is $curtime. Waiting for $nexttime\n";
    if ($curtime < $nexttime) {
	sleep($nexttime - $curtime);
    }

}




# this routine gets the radar images and merges them together.
# do what we can to get the image that we want.  Right now wunderground.com is 
# fairly reliable about having modified times being within 10 - 20 seconds after
# the printed times on the images but the image typically shows up several minutes
# after the modified time.
# This routine attempts to get the right image but tries to be relatively fault 
# tolerant.
BEGIN {
    @imgs;
    @modified_times;

sub create_image {
    my $imgtime = shift();
    my $ua = LWP::UserAgent->new;
    $ua->timeout(20);

    my @urls = ('http://icons.wunderground.com/data/640x480/2xradara4.gif',
		'http://icons.wunderground.com/data/640x480/2xradara5.gif',
		'http://icons.wunderground.com/data/640x480/2xradarb4.gif',
		'http://icons.wunderground.com/data/640x480/2xradarb5.gif');
    
    my @gotten;

    for (my $retry = 0; $retry < $retry_max; ++$retry) {
	my $gotten_all = 1;
	for (my $i = 0; $i < scalar(@urls); ++$i) {
	    next if $gotten[$i];
            
            # if I've already grabbed an image (but not the one I want) just get a header first
	    if (defined($imgs[$i])) {  
		my $head_response = $ua->head($urls[$i]);
		unless ($head_response->is_success) { print "head $url[$i] failed\n"; $gotten_all = 0; next; }
		$last_mod = $head_response->last_modified;
		
		# we're not happy with the image unless the modified time
		# sits within the $img_mod_time_* window.  But if we've
		# got a new image we'll download it regardless.
		unless (($last_mod - $imgtime < $img_mod_time_late) &&
		    ($imgtime - $last_mod < $img_mod_time_early)) {
		    $gotten_all = 0;
		    print "modified time for header of $urls[$i] is $last_mod, wanted $imgtime\n";
		    if ($last_mod == $modified_times[$i]) {
			next;
		    }
		}
	    }

	    # if I'm here it means that I should get a new copy of the image
	    my $response = $ua->get($urls[$i]);
	    unless ($response->is_success) { print "get $url[$i] failed\n"; $gotten_all = 0; next; }
	    $imgs[$i] = $response->content;
	    $last_mod = $response->last_modified;
	    $modified_times[$i] = $last_mod;
	    print ("last_mod: $last_mod, ideal: $imgtime\n");
	    if (($last_mod - $imgtime < $img_mod_time_late) &&
		($imgtime - $last_mod < $img_mod_time_early)) {
		$gotten[$i] = 1;
	    } else {
		$gotten_all = 0;
		print "modified time for $urls[$i] is $last_mod, wanted $imgtime\n";
	    }
	}
	last if $gotten_all;
	sleep($retry_period);
    }

    # at this point we've gotten the best images we're going to get so merge 
    # them into one large image.

    my $map = Image::Magick->new;
    $map->Set(size=>"1090x675");
    $map->ReadImage('xc:black');

    my $sm = Image::Magick->new(magick=>'gif');
    $sm->BlobToImage($imgs[0]);
    if ($old_imagemagick) {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'-81', 'y'=>'-6');
    } else {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'-80', 'y'=>'-5');
    }
    @$sm = ();
    $sm->BlobToImage($imgs[1]);
    if ($old_imagemagick) {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'450', 'y'=>'-28');
    } else {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'450', 'y'=>'-27');
    }
    @$sm = ();
    $sm->BlobToImage($imgs[3]);
    $sm->Crop('y'=>'30');
    $map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'333', 'y'=>'331');
    @$sm = ();
    $sm->BlobToImage($imgs[2]);
    $sm->Crop('width'=>'635');
    $sm->Crop('y'=>'30');
    if ($old_imagemagick) {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'-2', 'y'=>'225');
    } else {
	$map->Composite('image'=>$sm, 'compose'=>'Over', 'x'=>'-1', 'y'=>'225');
    }
    my $filename = filename($imgtime, 1);
#    my $filename = "map_" . $imgtime . ".png";
    print "writing $filename\n";
    $map->write($filename);
}
}

sub filename {
    my $time = shift();
    my $check_dir = shift();

    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
	localtime($time);

    if ($archive_all_images) {
	my $year_dir = $year + 1900;
	my $dir = sprintf("%04d-%02d-%02d", $year + 1900, $mon + 1, $mday);
	my $file = sprintf("%s_%02d%02d.gif", $dir, $hour, $min);
	
	if ($check_dir) {
	    unless (-d $year_dir) {
		mkdir $year_dir;
	    }
	    unless (-d "$year_dir/$dir") {
		mkdir "$year_dir/$dir";
	    }
	}
	
	return "$year_dir/$dir/$file";
    }

    my $dir = sprintf("%04d-%02d-%02d", $year + 1900, $mon + 1, $mday);
    my $file = sprintf("%s_%02d%02d.gif", $dir, $hour, $min);
    return $file;
}

sub remove_image {
    my $time = shift;
    my $name = filename($time);
    unlink $name;
}

sub create_animation {
    my $start = shift;
    my $frames = shift;

    my $syscmd = "gifsicle -O2 -d 30 --loop=0 ";

    for (my $i = 0; $i < $frames; ++$i) {
	my $inname = filename($start + $i * $period);
	$syscmd .= " -d 100 " if $i == $frames - 1;  # add an extra end delay
	$syscmd .= $inname . " ";
    }
    $syscmd .= "> current_anim.gif";
    system $syscmd;
    system "cp current_anim.gif $animation_destination";

}
