#!/usr/bin/perl

use Image::Magick;

$edge=150;
$graphics = "original";
$thumbs = 0;

while ($ARGV[0] =~ /^([-\+].*)/) {
    $k = $1;
    shift @ARGV;
    if ($k =~ /^-e(\d+)$/) { $edge = $1; }
    if ($k =~ /^-n$/) { $test = 1; }
    if ($k =~ /^-2016$/) { $graphics = "2016"; }
    if ($k =~ /^-2005$/) { $graphics = "2005"; }
    if ($k =~ /^\+2005$/) { $graphics = "both"; }
    if ($k =~ /^-t$/ || $k =~ /^-thumb$/) { $thumbs = 1; }
    if ($k =~ /^-p$/ || $k =~ /^-pdf$/) { $pdfs = 1; }
}
$name = $ARGV[0];

$wallnudge = 0.15*$edge;

# The numbers below are percentages, so don't be a Took and forget
# to divide by 3.  That would be silly.

%Crusher = (
    "1,1" => "+44+33",
    "2,1" => "+44+33", "2,2" => "+44+55",
    "3,1" => "+44+33", "3,2" => "+33+53", "3,3" => "+56+53",
    "4,1" => "+33+33", "4,2" => "+56+33", "4,3" => "+33+55", "4,4" => "+56+55");
%Crusher_Mega = (
    "1,1" => "+65+65",
    "2,1" => "+29+65", "2,2" => "+100+65",
    "3,1" => "+29+65", "3,2" => "+65+65", "3,3" => "+100+65");
%Multi = (
    "1,1" => "+42+2",
    "2,1" => "+34+2", "2,2" => "+50+2",
    "3,1" => "+25+2", "3,2" => "+41+2", "3,3" => "+57+2",
    "4,1" => "+17+2", "4,2" => "+33+2", "4,3" => "+49+2", "4,4" => "+65+2");
%Wall_PT = (
    "1,1" => "+42+2",
    "2,1" => "+34+2", "2,2" => "+50+2",
    "3,1" => "+25+2", "3,2" => "+41+2", "3,3" => "+57+2",
    "4,1" => "+15+2", "4,2" => "+31+2", "4,3" => "+47+2", "4,4" => "+63+2");
%Flamer = (
    "2,1" => "+27+29", "2,2" => "+57+29",
    "3,1" => "+43+14", "3,2" => "+27+33", "3,3" => "+57+33",
    "4,1" => "+30+14", "4,2" => "+54+14", "4,3" => "+27+33", "4,4" => "+57+33");
%Flamer_Long = (
    "1,1" => "+40+44",
    "2,1" => "+24+49", "2,2" => "+55+49",
    "3,1" => "+40+34", "3,2" => "+24+63", "3,3" => "+55+63");
%Laser = (
    "1,1" => "+0",
    "2,1" => "-22.5", "2,2" => "+22.5",
    "3,1" => "-32", "3,2" => "+0", "3,3" => "+33");

foreach $k ("Crusher", "Flamer", "Flamer_Long", "Laser", "Multi", "Wall_PT") {
    foreach (keys(%$k)) {
	$$k{$_} =~ s!([0-9\.]+)!($1*$edge/100)!eg;
    }
}

@full_tiles = (
    "Red","Red_TL","Red_TR","Red_Start","Red_JL","Red_JR","Red_JB","Red_J3",
    "Blue","Blue_TL","Blue_TR","Blue_Start","Blue_JL","Blue_JR","Blue_JB","Blue_J3",
    "Black",
    "Water","Water_Current","Water_Current_L","Water_Current_R",
    "Water_Current_JL","Water_Current_JR","Water_Drain","Water_Double_Spanner",
    "Gold","Gold_TL","Gold_TR","Gold_JL","Gold_JB","Green",
    "Radioactive_Waste","Radioactive_Waste_Drain","Radioactive_Waste_End_Barrel",
    "Radioactive_Waste_End","Radioactive_Waste_Middle","Radioactive_Waste_Edge",
    "Rust","Sandslip"
    );    

%tweakings = (
    "Floor"         => { suffix => [1,2,2,3], angle => [0,90,180,270] },
    "Rust"          => { suffix => [1,2,3,4], angle => [0,90,180,270] },
    "Oil_Splash"    => { suffix => [2],       angle => [0,90,180,270] },
    "Water"         => { suffix => [1,2],     angle => [0,90,180,270] },
    "Oil_Drop"      => { suffix => [1,2],     angle => [0,90,180,270] },
    "Oil_Middle"    => { suffix => [1,2,3],   angle => [0,180]        },
    "Pull"          => { suffix => [1,2,3],   angle => [0,180]        },
    "Repulsor"      => { suffix => [1,2]                              },
    "Water_Current" => { suffix => [1,2]                              },
    "Lava"          => { suffix => [1,2]                              },
    "Oil_Start"     => { suffix => [1,2]                              },
    "Oil_End"       => { suffix => [1,2]                              },
    "Oil_Stop"      => { suffix => [1,2]                              },
    "Oil_L"         => { suffix => [1,2]                              },
    "Pit"           => {                      angle => [0,90,180,270] },
    "Floor_Cracked" => {                      angle => [0,90,180,270] },
    "Floor_Metal"   => {                      angle => [0,90,180,270] }
    );

$i = 0; $j = 0;
while(<>) {
    next if /^#/;
    next if !/./;
    chomp;
    if (/Title: (.*)/) {
        $title = $1;
	@title = split /,/, $title;
        for(my $i=0; $i<@title; $i++) {
            $title[$i] =~ /(\[.*\]) ?(negate)?/;
            $title[$i] = $1;
            if ($2) { $negate[$i] = 1; } else { $negate = 0; }
        }
	next; }
    if (/(\d+)x(\d+)/) { $h = $1; $w = $2; next; }

    $floor[$i][$j] = $_;
#    print $i." ".$j."\n";
    $j++;
    if ($j == $w) { $i++; $j = 0; }
}

if ($test) {
    print "Name: $name\n".
      "Title: $title\n".
      "Size: ${h}x$w\n\n"; 
}

if (@title>0) {
    $i = 1;
    foreach (@title) {
        $ps = "$title[$i-1]";
	$ps .= << 'EOF';
/text exch def
/outertilesize 72 def
/innertilesize 66 def
/leading 1.1 def
/Helvetica-Bold findfont setfont
/capheight (A) 0 0 moveto true charpath flattenpath pathbbox 4 1 roll pop pop pop def
/ptsize innertilesize text length 1 sub leading mul capheight add div def 
0.2 outertilesize mul dup ptsize lt { /ptsize exch def } { pop } ifelse
text {
  stringwidth pop innertilesize exch div
  dup ptsize lt { /ptsize exch def } { pop } ifelse
} forall
/height text length 1 sub leading mul capheight add ptsize mul def
/ytop outertilesize height add 2 div ptsize capheight mul sub def
currentfont ptsize scalefont setfont
text {
  outertilesize 2 div ytop moveto
  dup stringwidth pop 2 div neg 0 rmoveto show
  /ytop ytop ptsize leading mul sub def
} forall
showpage
EOF

        if (@title == 1) { $i = ""; }

	$titlepng = Image::Magick->new(magick=>"ps",depth=>"1",page=>"72x72",density=>"600", units=>"PixelsPerInch");
	$titlepng->BlobToImage($ps);
	$titlepng->Set(depth=>"8");
	
        if (!$negate[$i-1]) {
	    $titlepng->Transparent(color=>"white");
	    $titlepng->Resize(geometry=>$edge.'x'.$edge);
	}
        else { 
	    $titlepng->Negate();
	    $titlepng->Transparent(color=>"black");
	    $titlepng->Resize(geometry=>$edge.'x'.$edge);
        }
	$stored{"Title$i"} = $titlepng->Clone();
        if (@title > 1) { $i++; }

    }
}

$black_tile = Image::Magick->new(size=>$edge.'x'.$edge);
$black_tile->Read('xc:black');

$transparent_tile = Image::Magick->new(size=>$edge.'x'.$edge);
$transparent_tile->Read('xc:transparent');

for ($pass=0; $pass < 2; $pass++){
    if (($graphics eq "original" || $graphics eq "both") && $pass == 0) {
	$gset = "";
	$outputname = $name;
    }
    elsif (($graphics eq "2005" || $graphics eq "both") && $pass == 1) {
	$gset = "2005";
	$outputname = $name.".2005";
	
	for (keys %stored){
	    if (!/^Title\d*/) { delete $stored{$_}; }
	}
    }
    elsif ($graphics eq "2016" && $pass == 1) {
	$gset = "2016";
	$outputname = $name.".2016";
	
	for (keys %stored){
	    if (!/^Title\d*/) { delete $stored{$_}; }
	}
    }
    else { next; }
    
    print "Graphics: ";
    if ($gset eq "") { print "original\n"; }
    elsif ($gset eq "2005") { print "2005\n"; }
    elsif ($gset eq "2016") { print "2016\n"; }
    
    $board = Image::Magick->new;

    for ($i=0; $i<$h; $i++) {
	$row = Image::Magick->new;
	for ($j=0; $j<$w; $j++) {
	    $tile = $black_tile->Clone();
	    @elements = ();
	    if ($test) { printf("Row %2i, Col %2i :  ",$i+1,$j+1); }
	    
	    foreach (split /,/, $floor[$i][$j]) {
		next if ($_ eq "aaa");
		s/^ *//;
		s/ +/ /g;
		($element,@rest) = split / /; 
		$rotate = 0; $translate = ""; $resize = "";
		$n = 0; $e = 0; $shrink = 84;

		foreach (@rest) {
		    if (/^0|90|180|270$/) { $rotate = $_; }
		    
		    if (/x([\d\.]+)/) {
			$shrink = $1;
			$resize = ($shrink*$edge/100)."x".($shrink*$edge/100);
			$n = $e = (100-$shrink)/2;
		    }
		    
		    if (/[newsc]/) { 
			$resize = ($shrink*$edge/100)."x".($shrink*$edge/100);
			$n = 8; $e = 8;
		    }
		    
		    if (/N([\d\.]*)/i) { $n -= $1 || 8 ; }
		    if (/S([\d\.]*)/i) { $n += $1 || 8 ; }
		    if (/E([\d\.]*)/i) { $e += $1 || 8 ; }
		    if (/W([\d\.]*)/i) { $e -= $1 || 8 ; }
		    
		    if (/[NEWSCx]/i) {
			$translate = ($e<0?"-":"+").(abs($e)*$edge/100).
			  ($n<0?"-":"+").(abs($n)*$edge/100);
		    }
		    
		}
		
		push @elements, [$element,$rotate,$translate,$resize];
		
	    }
	    
	    if (!$elements[1][2] && !$elements[1][3]) {
		foreach (@full_tiles) {
		    if ($elements[1][0] eq $_) { 
			$elements[0][0] = ""; 
			last;
		    }
		}
	    }
	    
	    
	    foreach (@elements) {
		
		($element,$rotate,$translate,$resize) = @$_;
		if (!$element) { next; } 
		if ($test) { print "$element".($rotate?", $rotate":"").($translate?", $translate":"")."; "; }
		
# Some elements have different patterns, or could be rotated randomly,
# which would make things prettier.  Available choices are in %tweakings
# above.
		
		if ($tweakings{$element}) {
		    if ($tweakings{$element}{angle}) {
			$rotate ||= rnd(@{$tweakings{$element}{angle}});
		    }
		    if ($tweakings{$element}{suffix}) {
			$element .= rnd(@{$tweakings{$element}{suffix}});
		    }
		}
		
		$pieces = Image::Magick->new(size=>'${edge}x$edge');
		
		if (defined($stored{$element})) {
		    print $element."\n";
		    $pieces = $stored{$element}->Clone();
		}
		
# Pushers, Crushers, Flamers and Lasers can come in several different forms.
# But rather than having dozens of similar pngs saved, let's keep only a few
# and do stuff here.  It looks icky, of course.
		
		elsif ($element =~ /^(Pit|Pusher|Big_Pusher|Magnet)_(\d+)(_W)?/) {
		    my $element = $1; $phases = $2; $wall = $3;
		    
		    $pieces->Read(filename($element."_Blank",$gset));
		    
		    foreach (split //, $phases) {
			$tmp = Image::Magick->new;
			$tmp->Read(filename($element."_$_",$gset));
			$pieces->Composite(image=>$tmp,gravity=>"NorthWest");
		    }
		    if ($element =~ /Pusher/ && $wall) {
			$tmp = $pieces->Clone();
			$pieces = $transparent_tile->Clone();
			$pieces->Composite(image=>$tmp, geometry=> "+0-".$wallnudge,gravity=>"NorthWest");
		    }
		}
		
		elsif ($element =~ /^(Crusher|Flamer|Crusher_Mega|Flamer_Long|Multi|Wall_PT)_(\d+)(r)?/) {
		    my $element = $1;
		    @phases = split //, $2;
		    $r = $3 || "";
		    
		    $pieces->Read(filename($element."_Blank",$gset));
		    
		    for ($n=0; $n<@phases; $n++) {
			$tmp = Image::Magick->new;
			$tmp->Read(filename($element."_$phases[$n]$r",$gset));
			$pieces->Composite(image=>$tmp,
			    geometry=>$$element{scalar(@phases).",".($n+1)},gravity=>"NorthWest");
		    }
		}   
		
		elsif ($element =~ /^(Laser|GLaser|Gun|GunL|Gun_R|MGun|RepelGun)(\d)?(_W)?$/) {
		    my $element = $1; $d = $2 || 1; $wall = $3 || 0;
		    
		    $pieces = $transparent_tile->Clone();
		    $tmp = Image::Magick->new;
		    $tmp->Read(filename($element,$gset));
		    for ($n = 1; $n<=$d; $n++) {
			$pieces->Composite(image=>$tmp,
			    geometry=>$Laser{"$d,$n"}."-".($wall?$wallnudge:0),gravity=>"NorthWest");
		    }
		}
		
		else { $pieces->Read(filename($element,$gset)); }
		
		if (!defined($stored{$element})) {
		    $stored{$element} = $pieces->Clone();
#		$stored{$element}->Display();
		}
		
		if ($rotate) { $pieces->Rotate(degrees=>$rotate); }
		
		if ($resize) { $pieces->Resize(geometry=>$resize); }
		
		if ($translate) {
		    $tmp = $transparent_tile->Clone();
		    $tmp->Composite(image=>$pieces,geometry=>$translate, gravity=>"NorthWest");
		    $pieces = $tmp->Clone();
		}
		
		$tile->Composite(image=>$pieces, gravity=>"NorthWest");
		
	    }
	    push(@$row,@$tile);
	    if ($test) { print "\n"; }
	}
	if ($test) { print "\n"; }
	
	push(@$board,$row->Append(stack=>"false"));
    }
    $output = $board->Append(stack=>"true");
    $output->Set(depth=>'8');
    if ($test) { print "Writing board: $name\n"; }
    $stoat = $output->Write(filename=>"$outputname.png");

    if ($pdfs) {
	print "Making pdfs\n";
	
	if ($w ==12 && $h == 12) {
	    
	    $pdfpage = Image::Magick->new(depth=>'8');
	    $pdfpage->[0] = $output->Clone();
	    $pdfpage->[0]->Crop(geometry=>'900x900+0+0');
	    $pdfpage->[0]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150", compression=>"LosslessJPEG");
	    $pdfpage->[1] = $output->Clone();
	    $pdfpage->[1]->Crop(geometry=>'900x900+900+0');
	    $pdfpage->[1]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150", compression=>"LosslessJPEG");
	    $pdfpage->[2] = $output->Clone();
	    $pdfpage->[2]->Crop(geometry=>'900x900+0+900');
	    $pdfpage->[2]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150", compression=>"LosslessJPEG");
	    $pdfpage->[3] = $output->Clone();
	    $pdfpage->[3]->Crop(geometry=>'900x900+900+900');
	    $pdfpage->[3]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150", compression=>"LosslessJPEG");
	    $pdfpage->Write(filename=>"$outputname.4.tiff");
	    system("tiff2pdf", "-j", "-q100", "-pA4", "-t", "$outputname", "-o",
		"$outputname.4.pdf", "$outputname.4.tiff");
	    system("rm", "$outputname.4.tiff");
	    
	    $pdfpage = Image::Magick->new(depth=>'8');
	    $pdfpage->[0] = $output->Clone();
	    $pdfpage->[0]->Crop(geometry=>'900x1200+0+0');
	    $pdfpage->[0]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150");
	    $pdfpage->[1] = $output->Clone();
	    $pdfpage->[1]->Crop(geometry=>'900x1200+900+0');
	    $pdfpage->[1]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150");
	    $thirdpage = Image::Magick->new;
	    $thirdpage->[0] = $output->Clone();
	    $thirdpage->[0]->Crop(geometry=>'900x600+0+1200');
	    $thirdpage->[0]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150");
	    $thirdpage->[1] = Image::Magick->new(size=>'900x150');
	    $thirdpage->[1]->Read('xc:white');
	    $thirdpage->[2] = $output->Clone();
	    $thirdpage->[2]->Crop(geometry=>'900x600+900+1200');
	    $thirdpage->[2]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150");
	    $pdfpage->[2] = $thirdpage->Append(stack=>"true");
	    $pdfpage->Write(filename=>"$outputname.3.tiff");
	    system("tiff2pdf", "-j", "-q100", "-pA4", "-t", "$outputname", "-o",
		"$outputname.3.pdf", "$outputname.3.tiff");
	    system("rm", "$outputname.3.tiff");
	}
	
	if (($w ==5 && $h == 10) || ($w == 7 && $h == 7)) {
	    
	    $pdfpage = Image::Magick->new(depth=>'8');
	    $pdfpage->[0] = $output->Clone();
	    $pdfpage->[0]->Set(page=>'+0+0', units=>"PixelsPerInch", density=>"150x150");
	    $pdfpage->Write(filename=>"$outputname.tiff");
	    system("tiff2pdf", "-j", "-q100", "-pA4", "-t", "$outputname", "-o",
		"$outputname.pdf", "$outputname.tiff");
	    system("rm", "$outputname.tiff");
	    
	}

    }
    
    if ($thumbs) { 
	print "Making thumbnails\n";
	$output->Resize(geometry=>($w*35)."x".($h*35));
	$output->Write(filename=>"$outputname.small.jpg");
	$output->Resize(geometry=>($w*15)."x".($hx15));
	$output->Write(filename=>"$outputname.thmb.jpg");
    }
}

sub rnd { return $_[int(rand(@_))]; }

sub filename {
    my ($file,$gset) = @_;
    if ($gset == "2005" && -f "$edge/2005-$file.png") {
	return "$edge/2005-$file.png";
	}
    elsif ($gset == "2016" && -f "$edge/2016-$file.png") {
	return "$edge/2016-$file.png";
	}
    else { return "$edge/$file.png"; }
}