#!/usr/bin/perl
# Usage: svg-parser.pl [EPSG] [fichier.svg] [bbox]
use XML::Parser;
use Geo::OSR;

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $tag_source = "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : " . ($year + 1900);

my @bbox_lbr93;
my @bbox_pts;
# Hash qui à chaque point associe une ref
my %points;
my @ways;
my @relations;
my $refnodes = 0;
my $refways = 0;
my $refrel = 0;

my $source = Geo::OSR::SpatialReference->create ();
my $target = Geo::OSR::SpatialReference->create ();

$source->ImportFromEPSG ($ARGV[0]);
$target->ImportFromEPSG ('4326');
my $transf = new Geo::OSR::CoordinateTransformation ($source, $target);

my $parser = new XML::Parser ( Handlers => {
    Start => \&hdl_start,
    End   => \&hdl_end,
    Default => \&hdl_def
			       });
my $surface = 0;

sub hdl_start {
    my  ($p, $elt, %atts) = @_;
    @bbox_lbr93 = ($ARGV[2],$ARGV[3],$ARGV[4],$ARGV[5]);
    $surface = 1  if ($surface == 0 && $elt eq 'g' && $atts{'id'} eq 'surface0');
    if ($surface && $elt eq 'path' )
    {
	my @m  = get_matrix ($atts{'transform'});
	if ($atts{'style'} =~ m/fill:rgb\(100%,[^0]/)
	{
	    my $s = $atts{'d'};
	    do {
		my @points = format_point (\$s,@m);
		if (!defined(@bbox_pts))
		{
		    @bbox_pts = minmax(@points) if ($atts{'style'} =~ m/rgb\(100%,100%,100%\)/);
		}
		elsif (defined(@points))
		{
		    # On précède les refs associées au bâtiments sans mur par un -
		    # rgb(100%,89.803922%,60%)) : sans mur
		    # rgb(100%,80%,20%) : avec mur
		    $relations[$refrel] .= (($atts{'style'} =~ m/rgb\(100%,89/) ? "-" : "") ."$refways ";
		    new_way(@points);
		}
	    } while ($s =~ m/M (-?\d*\.?\d*) (-?\d*\.?\d*) L/);
	    $refrel++;
	}
    }
}

sub hdl_end {}

sub hdl_def {}

sub format_point {
    my ($s,@m) = @_;
    my @points;
    return unless $$s =~ s/^M //;
    $points[0] = transform_point ($s,@m);
    my $i = 1;
    while ($$s =~ s/^L //)
    {
	$points[$i] = transform_point ($s,@m);
	$i += 1;
    }
    $$s =~ s/^Z //;
    return @points
}

sub transform_point {
    my ($s,@m) = @_;
    my $p;

    ($p->[0],$p->[1]) = $$s =~ m/(-?\d*\.?\d*) (-?\d*\.?\d*) ?/;
    $$s =~ s/(-?\d*\.?\d*) (-?\d*\.?\d*) ?//;

    ($p->[0],$p->[1]) = (($m[0]*$p->[0] +  $m[2]*$p->[1] + $m[4]),($m[1]*$p->[0] +  $m[3]*$p->[1] + $m[5]));

    if (defined(@bbox_pts))
    {
	($p->[0],$p->[1]) = (
	    (($p->[0] - $bbox_pts[0]) * ($bbox_lbr93[2]-$bbox_lbr93[0])/($bbox_pts[2]-$bbox_pts[0]) + $bbox_lbr93[0]),
	    (($p->[1] - $bbox_pts[1]) * ($bbox_lbr93[1]-$bbox_lbr93[3])/($bbox_pts[3]-$bbox_pts[1]) + $bbox_lbr93[3])
	    );
	return ($transf->TransformPoint ($p->[0],$p->[1]));
    }
    else {
	return $p;
    }
}

sub get_matrix {
    my ($s) = @_;
    return split (/,/, $s) if $s =~ s/matrix\((.*)\)/$1/;
    return (1,0,0,1,0,0)
}

sub minmax {
    my @nodes = @_;
    my $xmin;
    my $ymin;
    my $xmax;
    my $ymax;
    my $node;
    foreach $node (@nodes) {
	$xmin = $node->[0] if ($node->[0] < $xmin);
	$ymin = $node->[1] if ($node->[1] < $ymin);
	$xmax = $node->[0] if ($node->[0] > $xmax);
	$ymax = $node->[1] if ($node->[1] > $ymax);
    }
    return ($xmin,$ymin,$xmax,$ymax)
}

sub new_point {
    my ($lat,$lon) = @_;
    if (!defined($points{"$lon,$lat"}))
    {
	$points{"$lon,$lat"} = $refnodes;
	$refnodes++;
    }
    $ref = $points{"$lon,$lat"};
}

sub new_way {
    my (@points) = @_;
    foreach $node (@points) {
	($lon,$lat) = ($node->[0],$node->[1]);
	new_point($lat,$lon);
	my $ref = $points{"$lon,$lat"};
	$ways[$refways] .= "$ref ";
    }
    $refways++;
}

$parser->parsefile($ARGV[1]);

my $bbox_wgs84_min = ($transf->TransformPoint (@bbox_lbr93[0,1]));
my $bbox_wgs84_max = ($transf->TransformPoint (@bbox_lbr93[2,3]));
print "<?xml version='1.0' encoding='UTF-8'?>\n";
print "<osm version='0.6' generator='plop'>\n";
print "<bounds minlat=\"$bbox_wgs84_min->[1]\" minlon=\"$bbox_wgs84_min->[0]\" maxlat=\"$bbox_wgs84_max->[1]\" maxlon=\"$bbox_wgs84_max->[0]\"/>\n";
foreach $node (keys %points)
{
    ($lon,$lat) = split (/,/, $node);
    $ref = -1 - $points{$node};
    print "<node id=\"$ref\" lat=\"$lat\" lon=\"$lon\"/>\n";
}

foreach $i (0..$#relations)
{
    my @relways = (split (/ /,$relations[$i]));
    if (@relways >1) {
	foreach $i (@relways)
	{
	    my $j = abs $i;
	    my $refway = -1-$j;
	    print "<way id=\"$refway\">\n";
	    foreach $node (split (/ /,$ways[$j]))
	    {
		my $ref = -1 - $node;
		print " <nd ref=\"$ref\"/>\n";
	    }
	    print " <tag k=\"source\" v=\"$tag_source\"/>\n";
	    if ($i == $relways[0])
	    {
		print " <tag k=\"building\" v=\"yes\"/>\n";
		print " <tag k=\"wall\" v=\"no\"/>\n" if ($i < 0);
	    }
	    print "</way>\n";
	}
	my $refrel = -1-$i;
	print "<relation id=\"$refrel\">\n";
	print " <tag k=\"type\" v=\"multipolygon\"/>\n";
	foreach $way (@relways)
	{
	    my $j = abs $way;
	    my $ref = -1-$j;
	    if ($way == $relways[0]) {
		print " <member type=\"way\" ref=\"$ref\" role=\"outer\"/>\n";
	    }
	    else {
		print " <member type=\"way\" ref=\"$ref\" role=\"inner\"/>\n";
	    }
	}
	print "</relation>\n";
    }
    else
    {
	my $j = abs $relways[0];
	my $refway = -1 - $j;
	print "<way id=\"$refway\">\n";
	foreach $node (split (/ /,$ways[$j]))
	{
	    my $ref = -1 - $node;
	    print " <nd ref=\"$ref\"/>\n";
	}
	print " <tag k=\"source\" v=\"$tag_source\"/>\n";
	print " <tag k=\"building\" v=\"yes\"/>\n";
	print " <tag k=\"wall\" v=\"no\"/>\n" if ($relways[0] < 0);
	print "</way>\n";
    }
}
print "</osm>";