#!/usr/bin/perl -w
#
# this script scales the given BSB map to the desired DX and DY
#
# usage: scalemap.pl <dx> <dy> <kap-file-1> [...]

use Image::Magick;

# retrieves data from the .KAP file; returns a hash with the following
# keys: width, height, dx, dy, lat0, lon0, lat1, lon1
sub get_kap_data {
    my $line;
    my ($w, $h, $odx, $ody);
    my ($r1x, $r1y, $r1lat, $r1lon, $r2x, $r2y, $r2lat, $r2lon);
    my ($dlat, $dlon);
    my ($lat0, $lon0, $lat1, $lon1);
    
    if( !open(G, $_[0]) ) {
        return undef;
    }

    # some pattern matching and replacement magic follows
    while(!eof(G)) {
        $line = <G>;
        chomp $line;
        if($line =~ /RA=/) {
            $line =~ s/.*RA=//;
            ($w = $line) =~ s/([0-9]*),[0-9].*/$1/;
            ($h = $line) =~ s/[0-9]*,([0-9]*).*/$1/;
        }
        if($line =~ /DX=/) {
            $line =~ s/.*DX=//;
            ($odx = $line) =~ s/([0-9.]*).*/$1/;
        }
        if($line =~ /DY=/) {
            $line =~ s/.*DY=//;
            ($ody = $line) =~ s/([0-9.]*).*/$1/;
        }
        if($line =~ /REF/) {
            $line =~ s/REF[^,]*,//;
            if(!defined($r1x)) {
                ($r1x = $line) =~ s/([0-9]*),[0-9]*,[0-9.]*,[0-9.]*/$1/;
                ($r1y = $line) =~ s/[0-9]*,([0-9]*),[0-9.]*,[0-9.]*/$1/;
                ($r1lat = $line) =~ s/[0-9]*,[0-9]*,([0-9.]*),[0-9.]*/$1/;
                ($r1lon = $line) =~ s/[0-9]*,[0-9]*,[0-9.]*,([0-9.]*)/$1/;
            }
            else {
                ($r2x = $line) =~ s/([0-9]*),[0-9]*,[0-9.]*,[0-9.]*/$1/;
                ($r2y = $line) =~ s/[0-9]*,([0-9]*),[0-9.]*,[0-9.]*/$1/;
                ($r2lat = $line) =~ s/[0-9]*,[0-9]*,([0-9.]*),[0-9.]*/$1/;
                ($r2lon = $line) =~ s/[0-9]*,[0-9]*,[0-9.]*,([0-9.]*)/$1/;
                if(($r2x == $r1x) || ($r2y == $r1y) ||
                   ($r2lat == $r1lat) || ($r2lon == $r1lon)) {
                    # fuck: linear dependency of the reference points -
                    # we need another reference point
                    $r2x = undef;
                    $r2y = undef;
                    $r2lat = undef;
                    $r2lon = undef;
                }
            }
        }
        if(defined($odx) && defined($ody) && defined($w) && defined($h) &&
           defined($r1x) && defined($r1y) && defined ($r1lat) && defined($r1lon) &&
           defined($r2x) && defined($r2y) && defined ($r2lat) && defined($r2lon)) {
            # great: we have all values we need
            last;
        }
    }
    close(G);
    if(!(defined($odx) && defined($ody) && defined($w) && defined($h) &&
         defined($r1x) && defined($r1y) && defined ($r1lat) && defined($r1lon) &&
         defined($r2x) && defined($r2y) && defined ($r2lat) && defined($r2lon))) {
        # it seems this .KAP file was fucked up...
        return undef;
    }
    # calculate upper-left and lower-right lat and lon
    $dlat = abs(($r1lat - $r2lat)/($r1y - $r2y));
    $dlon = abs(($r1lon - $r2lon)/($r1x - $r2x));
    $lat0 = $r1lat + $dlat*$r1y;
    $lon0 = $r1lon - $dlon*$r1x;
    $lat1 = $r2lat - $dlat*($h - $r2y);
    $lon1 = $r2lon + $dlon*($w - $r2x);
    print "Size $w x $h, dx = $odx, dy = $ody\n";
    print "1 y pixel is $dlat degrees\n";
    print "1 x pixel is $dlon degrees\n";
    print "Upper-left coordinates ($lon0, $lat0)\n";
    print "Lower-right coordinates ($lon1, $lat1)\n";
    return (width=>$w,
            height=>$h,
            dx=>$odx,
            dy=>$ody,
            lat0=>$lat0,
            lon0=>$lon0,
            lat1=>$lat1,
            lon1=>$lon1);
}

# scale the original .KAP file: it requires pregenerated X.png (should
# have been created with bsb2png from libbsb package) and outputs
# X-out.png and X-out.txt
sub scale_kap {
    my ($pf, $of, $tf);
    my ($xr, $yr);
    my $ndx = $_[1];
    my $ndy = $_[2];
    my %kap_data;

    ($pf = $_[0]) =~ s/.KAP/.png/;
    ($of = $_[0]) =~ s/.KAP/-out.png/;
    ($tf = $_[0]) =~ s/.KAP/-out.txt/;

    # get data from the .KAP file
    %kap_data = get_kap_data($_[0]);
    if(!%kap_data) {
        die "Unable to get KAP data.\n";
    }
    
    # calculate scaling ratio
    $xr = $kap_data{dx}/$ndx;
    $yr = $kap_data{dy}/$ndy;

    print "Scaling ratio: xr = $xr, yr = $yr\n";

    # load the original png
    my $img = Image::Magick->new;
    $img->ReadImage($pf);
    # scale it
    $img->Resize(width=>int($kap_data{width}*$xr),
                 height=>int($kap_data{height}*$yr),
                 blur=>0.5,
                 filter=>"Quadratic");
    # save it to the new name
    $img->WriteImage($of);

    # create the map data file
    if( !open(F, ">$tf") ) {
        die("Unable to open data file.\n");
    }
    print F "$kap_data{lat0},$kap_data{lon0}\n";
    print F "$kap_data{lat1},$kap_data{lon1}\n";
    print F int($kap_data{width}*$xr) . "," . int($kap_data{height}*$yr) . "\n";
    close(F);
}

my $i;

# scale the maps for all arguments on the command line
for($i = 2; $i < @ARGV; $i++) {
    print "Processing file $ARGV[$i].\n";
    scale_kap($ARGV[$i], $ARGV[0], $ARGV[1]);
}
