#!/usr/bin/perl

use XML::Simple qw(:strict);

#print $ARGV[0] . $/;

my $ref = XMLin($ARGV[0], 
    ForceArray => 1, 
    KeyAttr => 1); 
#    KeyAttr => {'g' => 'path',  path => 'style', path => 'd'} );

my @viewbox = split (" ", $ref->{viewBox});
my $basename = $ARGV[0];
$basename =~ s/.svg$//;
$basename = "SVG". $basename;
print "// $basename autogenerated by svg2cpp\n";
print "#include \"SVGBase.h\"\n\n";

print "class $basename : public SVGBase {\n";
print "public:\n";
print "     $basename() : SVGBase(\"$basename\") {};\n";
print "    ~$basename() {};\n";
print "    virtual double getWidth();\n";
print "    virtual double getHeight();\n";
print "    virtual void renderInternal();\n";
print "};\n\n";

print "double\n$basename\:\:getWidth () {\n";
print "    return $ref->{width};\n";
print "}\n\n";

print "double\n$basename\:\:getHeight () {\n";
print "    return $ref->{height};\n";
print "}\n\n";

print "void\n$basename\:\:renderInternal () {\n";
$g = $ref->{g};
$count = 0;
foreach (@{$g}) {
    my $scale = $ref->{width} / $viewbox[2];
#    my $scale = 1;
    # we assume uniform scale
    if(defined $_->{style} && $_->{style}  =~ /display:none/) {
#        print STDERR "Style is none\n";
        next;
    }
    if (defined $_->{path}) {
        foreach (@{$_->{path}}) {
            print "    newpath($count);\n";
            &proc_path ($_->{style}, $_->{d}, $scale);
            $count++;
        }
    }
    if (defined $_->{rect}) {
        foreach (@{$_->{rect}}) {
            &proc_rect ($_->{style}, $_, $scale, $count);
            $count++;
        }
    }
}
print "}\n";
exit(0);

sub proc_rect {
    my $style = $_[0];
    my $rect = $_[1];
    my $scale = $_[2];
    my $count = $_[3];
    my @style_arr = split (';', $style);
    my %style_attr = ();
    foreach (@style_arr) {
        my @att = split (':', $_);
        $style_attr{$att[0]} = $att[1];
    }
# FIXME We support only fill.
    $fill_color = "0";
    $stroke_color = "0";
    $linewidth = "1.0";
    if (defined $style_attr{fill} && $style_attr{fill} ne "none") {
        $fill_color = "\"$style_attr{fill}\"";
    }
    if (defined $style_attr{stroke} && $style_attr{stroke} ne "none") {
        $stroke_color = "\"$style_attr{stroke}\"";
    }
    if (defined $style_attr{'stroke-width'} 
        && $style_attr{'stroke-width'} ne "none") {

        $linewidth = $style_attr{'stroke-width'};
    }
    $x = $scale * $rect->{x}; 
    $y = $scale * $rect->{y}; 
    $width = $scale * $rect->{width}; 
    $height = $scale * $rect->{height}; 
    print "    rect ($count, $x, $y, $width, $height, 
        $fill_color, $stroke_color, $linewidth);\n";
}

sub proc_path {
    my $style = $_[0];
    my $d = $_[1];
    my $scale = $_[2];
    my @style_arr = split (';', $style);
    my %style_attr = ();
    foreach (@style_arr) {
        my @att = split (':', $_);
        $style_attr{$att[0]} = $att[1];
    }
    # FIXME This split requires spaces, real SVG can be packed.
    my @d = split (' ', $d);
    my $lastX = 0.0;
    my $lastY = 0.0;
    my $i = 0;
    my $lastC = "";
    my $fisrtX = 0.0;
    my $fisrtY = 0.0;
    while ($i<=$#d) {
        my $c = $d[$i++];
        if ($c !~ /^[A-Za-z]$/) {
            $c = $lastC;
            $c = "l" if ($c eq "m");
            $c = "L" if ($c eq "M");
            $i--;
        }
        if ($c eq "m") {
            my ($x0, $y0)  = split (/,/, $d[$i++]);
            $lastX += $x0  * $scale;
            $lastY += $y0  * $scale;
            $firstX = $lastX;
            $firstY = $lastY;
            print "    moveto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "c") {
            my ($x1,$y1)  = split (/,/, $d[$i++]);
            my ($x2,$y2)  = split (/,/, $d[$i++]);
            my ($x,$y)  = split (/,/, $d[$i++]);
            $x1 = $lastX + $x1 * $scale;
            $y1 = $lastY + $y1 * $scale;
            $x2 = $lastX + $x2 * $scale;
            $y2 = $lastY + $y2 * $scale;
            $lastX += $x  * $scale;
            $lastY += $y  * $scale;
            print "    curveto($x1,$y1, $x2,$y2, $lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "C") {
            my ($x1,$y1)  = split (/,/, $d[$i++]);
            my ($x2,$y2)  = split (/,/, $d[$i++]);
            my ($x,$y)  = split (/,/, $d[$i++]);
            $x1 = $x1 * $scale;
            $y1 = $y1 * $scale;
            $x2 = $x2 * $scale;
            $y2 = $y2 * $scale;
            $lastX = $x  * $scale;
            $lastY = $y  * $scale;
            print "    // absolute\n";
            print "    curveto($x1,$y1, $x2,$y2, $lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "M") {
            my ($x0, $y0)  = split (/,/, $d[$i++]);
            $lastX = $x0  * $scale;
            $lastY = $y0  * $scale;
            print "    moveto($lastX, $lastY);\n";
            $lastC = $c;
            $firstX = $lastX;
            $firstY = $lastY;
            next;
        }
        if ($c eq "z" || $c eq "Z") {
            print "    closepath ();\n"; 
            $lastC = $c;
            $lastX = $firstX;
            $lastY = $firstY;
            next;
        }
        if ($c eq "l") {
            my ($x0, $y0)  = split (/,/, $d[$i++]);
            $lastX += $x0 * $scale;
            $lastY += $y0 * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "L") {
            my ($x0, $y0)  = split (/,/, $d[$i++]);
            $lastX = $x0  * $scale;
            $lastY = $y0  * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "H") {
            my $d = $d[$i++];
            $lastX = $d  * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "V") {
            my $d = $d[$i++];
            $lastY = $d  * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "h") {
            my $d = $d[$i++];
            $lastX += $d  * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
        if ($c eq "v") {
            my $d = $d[$i++];
            $lastY += $d  * $scale;
            print "    lineto($lastX, $lastY);\n";
            $lastC = $c;
            next;
        }
    }
    if (defined $style_attr{fill}) {
        if ($style_attr{fill} ne "none") {
            print "    color(\"$style_attr{fill}\");\n";
            print "    fill();\n"; 
        }
    }
    if (defined $style_attr{stroke}) {
        # todo calculate stroke.
        $stroke_width = $style_attr{'stroke-width'} * $scale;
        if ($style_attr{stroke} ne "none") {
            print "    color(\"$style_attr{stroke}\");\n";
            print "    stroke($stroke_width);\n"; 
        }
    }
}
