#!/usr/bin/perl
# Ikiwiki google maps API plugin
# cm@tahina.priv.at 20061001
package IkiWiki::Plugin::googlemaps;

use warnings;
use strict;
use IkiWiki;
use Data::Dumper;

my %googlemaps;
my $googlemaps_key = "";

my $gpsbabel = '/usr/bin/gpsbabel';

my %known_controls = (small => 'GSmallMapControl',
		      large => 'GLargeMapControl',
		      type => 'GMapTypeControl');

sub import { #{{{
	IkiWiki::hook(type => "preprocess", id => "googlemaps",
		call => \&preprocess);
	IkiWiki::hook(type => "filter", id => "googlemaps",
		call => \&filter);
	IkiWiki::hook(type => "pagetemplate", id => "googlemaps",
		call => \&pagetemplate);
	IkiWiki::hook(type => "format", id => "googlemaps",
		call => \&format);
}

sub preprocess (@) { #{{{
	my %params=@_;
	my $js = "";
	my $id;
	my $lat = $params{lat};
	my $lon = $params{lon};
	my $zoom = $params{zoom} || 13;
	my $width = $params{width} || 500;
	my $height = $params{height} || 300;
	my $controls = $params{controls} || '';
	my $mode = 'plain';
	my $center = $params{center} || '';
	my $tracklen = $params{tracklen} || 100;

	if($params{trackfile}) {
		$mode = 'track';
	}

	if($mode eq 'plain' || $center ne 'track') {
		$lat =~ /^-?[\d\.]+$/ || return "bad lat";
		$lon =~ /^-?[\d\.]+$/ || return "bad lon";
	}
	$width =~ /^\d+$/ || return "bad width";
	$height =~ /^\d+$/ || return "bad height";
	$zoom =~ /^\d+$/ || return "bad zoom";

	if(!@_) {
		return "";
	}

	if($params{key}) {
		$googlemaps_key = $params{key};
	}

	if(!$params{id}) {
		IkiWiki::debug("plugin googlemaps: no \"id\" param on $params{page}");
		return;
	}
	$id = $params{id};

	my($lon_min,$lon_max,$lat_min,$lat_max) =
	  (1000,-1000,1000,-1000);

	if($mode eq 'track') {
		my $file = $params{trackfile};
		$file =~ /^[\w\d\._\-]+$/ || return "bad trackfile name";

		$file = IkiWiki::bestlink($params{page}, $file);
		IkiWiki::add_depends($params{page}, $file);
		$file = IkiWiki::srcfile($file);

		$js .= "var track_$id = new GPolyline([\n";
		my @strings;

		my $cmd = "$gpsbabel -i gpx -f $file " .
		  "-x simplify,count=$tracklen -o csv -F -";
		open(CSV, "$cmd |") || return "open gpsbabel: $!";
		while(<CSV>) {
			my($lat,$lon,$name) = split(/\,\s*/, $_, 3);
			$lat =~ /^-?[\d\.]+$/ || return "bad lat from GPX";
			$lon =~ /^-?[\d\.]+$/ || return "bad lon from GPX";
			$lat_max = $lat if $lat > $lat_max;
			$lon_max = $lon if $lon > $lon_max;
			$lat_min = $lat if $lat < $lat_min;
			$lon_min = $lon if $lon < $lon_min;
			push(@strings,"new GLatLng($lat, $lon)");
		}
		close(CSV);
		$js .= join(",\n", @strings) . ']);
';
		if($center eq 'track') {
			$lat = ($lat_min + $lat_max) / 2;
			$lon = ($lon_min + $lon_max) / 2;
		}
	}

	$js .= "var map_$id = new GMap2(document.getElementById(\"map_$id\"));\n";
	for my $c (split(/,/,$controls)) {
		if(exists $known_controls{$c}) {
			$js .= "map_$id.addControl(new $known_controls{$c}());\n";
		}
	}


	$js .= "map_$id.setCenter(new GLatLng($lat, $lon), $zoom);\n";
	if($mode eq 'track') {
		$js .= 'map_' . $id . '.addOverlay(track_' . $id . ');
';
		if($center eq 'track') {
			$js .=
"var zoom = map_$id.getBoundsZoomLevel(new GLatLngBounds(new GLatLng($lat_min,$lon_min), new GLatLng($lat_max,$lon_max)));
map_$id.setCenter(new GLatLng($lat,$lon), zoom);\n";
		}
	}




	$googlemaps{$params{page}} .= $js;

	return "<div id=\"map_$id\" width=\"$width\" height=\"$height\"></div>";
}

sub filter (@) { #{{{
	my %params=@_;

	$googlemaps{$params{page}} = '';

	return $params{content};
} # }}}

sub pagetemplate (@) { #{{{
	my %params=@_;
	my $page=$params{page};
	my $template=$params{template};

	if($googlemaps{$page}) {
		if(!$googlemaps_key) {
			IkiWiki::debug("googlemaps: no key on page '$page'");
			return;
		}
		my $head_js = 
'<style type="text/css">
  v:* {
    behavior:url(#default#VML);
  }
</style>
<script src="http://maps.google.com/maps?file=api&v=2&key=' . $googlemaps_key . '"
            type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[

    function load() {
      if (GBrowserIsCompatible()) {
' . $googlemaps{$page} . '      }
    }
    //]]>
</script>';
		$template->param(head => $head_js)
		  if exists $googlemaps{$page} &&
		    $template->query(name => 'head');
		$template->param(body_parms =>
				 'onload="load()" onunload="GUnload()"')
		  if exists $googlemaps{$page} &&
		    $template->query(name => 'body_parms');
	}
}

sub format {
	my %params = @_;
	$params{content} =~ s/<div id="map_(\w+)" width="(\d+)" height="(\d+)">/<div id="map_$1" style="width: $2px; height: $3px">/g;
	return $params{content};
}

1;
