#!/usr/bin/perl

use GD;

%pieces = (
	   'thin' => {
	       name => 'thin',
	       connect_to => 'slot',
	       connections => [
			       {
				   type => 'tab',
				   x => 0,
				   y => 3.5,
				   rot => 0,
			       },
			       ],
	       points => [
			  { x => -8.5, y => 0, },
			  { x => -8.5, y => 3.5, },
			  { x => 8.5, y => 3.5, },
			  { x => 8.5, y => 0, },
			  { x => -8.5, y => 0, }, #same as #1
			  ],
	   },
	   'thick' => {
	       name => 'thick',
	       connect_to => 'slot',
	       connections => [
			       {
				   type => 'tab',
				   x => 0,
				   y => 6.0621778,
				   rot => 0,
			       },
			       ],
	       points => [
			  { x => -8.5, y => 0, },
			  { x => -8.5, y => 6.0622, },
			  { x => 8.5, y => 6.0622, },
			  { x => 8.5, y => 0, },
			  { x => -8.5, y => 0, }, #same as #1
			  ],
	   },
	   'tri' => {	
	       name => 'triangle',
	       connect_to => 'tab',
	       connections => [
			       {
				   type => 'slot',
				   x => -4.25,
				   y => 7.3612159,
				   rot => 300,
				   mx => 4.25,
				   my => 7.3612159,
				   mrot => 60,
			       },
			       ],
	       points => [
			  { x => -8.5, y => 0, },
			  { x => 8, y => 14.7224, },
			  { x => 8.5, y => 0, },
			  { x => -8.5, y => 0, }, #same as #1
			  ],
	   },
	   'square' => {
	       name => 'square',
	       connect_to => 'tab',
	       connections => [
			       {
				   type => 'slot',
				   x => -8.5,
				   y => 8.5,
				   rot => 270,
				   mx => 8.5,
				   my => 8.5,
				   mrot => 90,
			       },
			       {
				   type => 'slot',
				   x => 0,
				   y => 17,
				   rot => 0,
			       },
			       ],
	       points => [
			  { x => -8.5, y => 0, },
			  { x => -8.5, y => 17, },
			  { x => 8.5, y => 17, },
			  { x => 8.5, y => 0, },
			  { x => -8.5, y => 0, }, #same as #1
			  ],
	   },
	   );

%arm = (
	name => 'base',
	connect_to => '', #can't add bases onto anything!
	rotation => 0,
	connections => [
			{
			    type => 'slot',
			    x => 0,
			    y => 0,
			    rot => 0,
			},
			],
	points => [],
	);

add_pieces(\%arm,5);
to_img(\%arm);
#print to_string(\%arm) . "\n";

sub add_pieces {
    my($arm,$depth) = @_;
    return if($depth <= 0);
    foreach my $con (@{$arm->{connections}}) {
	next if($con->{empty});
	if($con->{filled}) {
	    add_pieces($con->{filled},1);
	} else {
	    my(@add_types) = ('empty',);
	    foreach my $p (keys %pieces) {
		if($pieces{$p}{connect_to} eq $con->{type}) {
		    push @add_types,$p;
		}
	    }
	    #print "Choosing between ".join(",",@add_types)."\n";
	    my($rand) = int (rand scalar @add_types);
	    my($add) = $add_types[$rand];
	    if($add eq "empty") {
		$con->{empty} = 1;
	    } else {
		my($rotation) = $arm->{rotation} + $con->{rot};
		$rotation -= 360 while($rotation >= 360);
		my($coord_x,$coord_y) = ($con->{x},$con->{y});
		$con->{filled} = {
		    name => $pieces{$add}{name},
		    connect_to => $pieces{$add}{connect_to},
		    rotation => $rotation,
		    x => $coord_x,
		    y => $coord_y,
		};
		foreach my $c (@{$pieces{$add}{connections}}) {
		    my($x,$y) = rotate_point($c->{x},$c->{y},$rotation);
		    $x += $coord_x;
		    $y += $coord_y;
		    my($mx,$my) = rotate_point($c->{mx},$c->{my},$rotation);
		    $mx += $coord_x;
		    $my += $coord_y;
		    push @{$con->{filled}{connections}},{
			type => $c->{type},
			x => $x,
			y => $y,
			rot => $c->{rot},
			mx => $mx,
			my => $my,
			mrot => $c->{mrot},
		    };
		}
		foreach my $p (@{$pieces{$add}{points}}) {
		    my($x,$y) = rotate_point($p->{x},$p->{y},$rotation);
		    $x += $coord_x;
		    $y += $coord_y;
		    push @{$con->{filled}{points}},{
			x => $x,
			y => $y,
		    };
		}
	    }
	}
    }
    add_pieces($arm,$depth-1);
}

sub to_string {
    my($obj) = @_;
    my($str) = $obj->{name} . $obj->{rotation} . "[";
    foreach my $con (@{$obj->{connections}}) {
	if($con->{filled}) {
	    $str .= "(" . to_string($con->{filled}) . ")";
	} else {
	    $str .= "(empty)";
	}
    }
    $str .= "]";
    return $str;
}

sub to_img {
    my($obj) = @_;
    $img = new GD::Image(300,300,1);
    $img->fill(10,10,color(223,223,223));
    draw_part($obj);
    print "Content-Type: image/png\n\n";
    binmode STDOUT;
    print $img->png;
}

sub draw_part {
    my($obj) = @_;
    my($i);
    my(@FUCKYOU) = @{$obj->{points}};
    for($i=0;$i<$#FUCKYOU;$i++) {
	my($pt1) = $obj->{points}[$i];
	my($pt2) = $obj->{points}[$i+1];
	$img->line($pt1->{x}+100,$pt1->{y}+100,$pt2->{x}+100,$pt2->{y}+100,color(0,0,0));
    }
    foreach my $con (@{$obj->{connections}}) {
	if($con->{filled}) {
	    draw_part($con->{filled});
	}
    }
    #$img->line($x*$hscale,0,$x*$hscale,$vscale*26,color(191,191,191));
    #$img->string(gdTinyFont,$x*$hscale+25,$vscale*26+5,"$mon $d",color($c,$c,$c));
}

sub color {
    my($r,$g,$b) = @_;
    if(!defined($pal{"$r\_$g\_$b"})) {
        $pal{"$r\_$g\_$b"} = $img->colorAllocate($r,$g,$b);
    }
    return $pal{"$r\_$g\_$b"};
}

sub rotate_point {
    my($x,$y,$angle) = @_;
    my $current_angle_rad = ($x == 0) ? (($y >= 0) ? 90 : 270) : atan2($y,$x);
    my $current_angle = degrees($current_angle_rad);
    my $new_angle = $angle+$current_angle;
    $new_angle -= 360 while($new_angle > 360);
    $new_angle += 360 while($new_angle < 0);
    my $new_angle_rad = radians($new_angle);
    my($dist) = sqrt($x*$x + $y*$y);
    my($newx) = cos($new_angle_rad)*$dist;
    my($newy) = sin($new_angle_rad)*$dist;
    return($newx,$newy);
}

sub degrees {
    return ($_[0]*180)/3.14159265358979323846;
}

sub radians {
    return ($_[0]*3.14159265358979323846)/180;
}
