#!/usr/bin/perl
# osm2xy.pl - Request tiles@home tiles covered by nodes in a .osm file
# Copyright 2007 Knut Arne Bjorndal
# Based on osm2xy.phps from jrreid

# TODO: Add configurable zoomlevel, and output an error on combination of z!=12 and --request
use warnings;
use strict;

use Getopt::Long;
use XML::SAX;
use IO::File;
use LWP::UserAgent;
use HTTP::Request::Common;
use Data::Dumper;

my($output, $surrounding, $request);
my $prio = 2;
GetOptions("output|o=s" => \$output,
	   "surrounding!" => \$surrounding,
	   "request|r" => \$request,
	   "prio=i" => \$prio);

unless( ( $output || $request ) &&
	$ARGV[0] && -f $ARGV[0]
	){
    usage();
}

my $handler = OSMHandler->new;
$handler->{req_surrounding} = $surrounding;
my $parser = XML::SAX::ParserFactory->parser( Handler => $handler );

$parser->parse_uri($ARGV[0]);

my( $fh, $ua );
if( $output ){ # Write tile list to file
    $fh = new IO::File($output, 'w');
} else { # Send request directly
    $ua = LWP::UserAgent->new;
    $ua->agent("bobkare_tilerequester/0.1");
}

my $total = 0;
foreach my $x ( keys( %{$handler->{tiles}} ) ){
    foreach my $y ( keys( %{$handler->{tiles}{$x}} ) ){
	$total++;

	if( $output ){ # Write tile list to file
	    $fh->print("$x $y\n");
	} else { # Send request directly
	    print "Requesting $x,$y\n";

	    my $req = HTTP::Request->new(GET => "http://dev.openstreetmap.org/~ojw/NeedRender/?x=$x&y=$y&priority=$prio&src=bobkare_tilerequester/0.0.1");
	    my $res = $ua->request($req);

	    unless( $res->is_success && $res->content =~ /OK/ ){
		warn "Request for $x $y failed! HTTP return code: ".$res->status_line.". API response: ".$res->content."\n";
	    }
	}
    }
}

print "Requests: $total\n";

sub usage() {
    die "Usage: $0 [--surrounding] --output=<tilelist.txt> | --request [--prio=NUM] <input.osm>\n";
}

package OSMHandler;
use warnings;
use strict;

use base qw(XML::SAX::Base);
use Data::Dumper;
use Math::Trig;
use POSIX;

sub start_element {
    my ($self, $el) = @_;
    return unless $el->{LocalName} eq 'node';

    my $lon = $el->{Attributes}{'{}lon'}{Value};
    my $lat = $el->{Attributes}{'{}lat'}{Value};

    my( $X, $Y ) = getTileNumber($lat, $lon, 12);

    $self->{tiles}{$X}{$Y} = 1;

    # Surrounding tiles
    if( $self->{req_surrounding} ){
	$self->{tiles}{$X+1}{$Y+1} = 1;
	$self->{tiles}{$X+1}{$Y-1} = 1;
	$self->{tiles}{$X-1}{$Y+1} = 1;
	$self->{tiles}{$X-1}{$Y-1} = 1;
    }
}

sub lat2y( $ ){
    my $lat = shift;

    my $limity = projectF(85.0511);
    my $y = projectF($lat);

    my $py = ($limity - $y) / (2*$limity);
    return $py;
}
sub projectF( $ ){
    my $lat = shift;

    $lat = deg2rad($lat);
    my $y = log(tan($lat) + (1/cos($lat)));
    return $y;
}
sub getTileNumber {
    my ($lat,$lon,$z) = @_;
    my $xtile = int( ($lon+180)/360 *2**$z ) ;
    my $ytile = int( (1 - log(tan($lat*pi/180) + sec($lat*pi/180))/pi)/2 *2**$z ) ;
    return(($xtile, $ytile));
}
