#!/usr/bin/perl
use strict;
use warnings;

#############################################################################
# A Useful script to perform math on google satellite coordinates.          #
# Usage:                                                                    #
# goog_math.pl <input> <dx> <dy>                                            #
# <input> - Required - Either a string or an X,Y,Zoom triplet. This will    #
#                      always be output in both formats                     #
# <dx> - Optional - Add (or subtract) the given value to the input. If this #
#                   field is present, the output will also be displayed     #
# <dy> - Optional - Y change. This field is optional if one wants only a dx.#
#############################################################################

################################
# Actual Code                  #
################################

my $zoom;
my $g0;
my $dx = 0;
my $dy = 0;
my $x0;
my $y0;
my $x1;
my $y1;
my $g1;
my $input = $ARGV[0]; shift;

my $input2;
my $input3;

if ($input && $input =~ m/^[qrst]+$/ ) {
   $g0 = $input;
   ($x0,$y0) = goog2xy($g0);
} else {
    $input2 = $ARGV[0];
    shift;
    $input3 = $ARGV[0];
    shift;
    if ($input && $input2 && $input3 && $input =~ m/^[0-9]+$/ && $input2 =~ m/^[0-9]+$/ && $input3 =~ m/^[0-9][0-9]?$/) {
        $x0 = $input;
        $y0 = $input2;
        $zoom = $input3;
        $g0 = xy2goog($x0,$y0,$zoom);
        if (substr($g0,0,1) ne "t") {
            die "Invalid zoom (first letter must be a \"t\")!\n";
        }
    } else {
        die "Invalid input! Enter either a satellite string or X,Y,Z\n";
    }
}

$input = $ARGV[0];
shift;
if ( $input &&  $input =~ m/^[\+\-]?[0-9]+$/) {
    $dx = $input;
}
$input = $ARGV[0];
shift;
if ( $input && $input =~ m/^[\+\-]?[0-9]+$/) {
    $dy = $input;
}


($x0,$y0) = goog2xy($g0);
$x1 = $x0 + $dx;
$y1 = $y0 + $dy;
$g1 = xy2goog($x1,$y1,length($g0));

print "$g0\t($x0,$y0)\n";
if ( $dx ) {
print "Shifted ($dx,$dy)\n";
print "$g1\t($x1,$y1)\n";
}

#####################
# Support Functions #
#####################
sub goog2xy {
  my ($goog) = @_;
  $_ = $goog;
  s/q/0/g;
  s/r/1/g;
  s/s/1/g;
  s/t/0/g;
  my $hst = $_;
  $_ = $goog;
  s/q/0/g;
  s/r/0/g;
  s/s/1/g;
  s/t/1/g;
  my $vst  = $_;
  my $hval = oct("0b" . $hst);
  my $vval = oct("0b" . $vst);
  return $hval, $vval;
}

sub xy2goog {
  my ($x, $y, $zoom) = @_;
  my @quadChars = qw/q t r s/;
  my $format    = '%0' . $zoom . 'b';
  my @xBits     = split(//, sprintf($format, $x));
  my @yBits     = split(//, sprintf($format, $y));
  my $res       = '';
  for (my $i = 0 ; $i < $zoom ; $i++) {
    $res .= $quadChars[ 2 * ($xBits[$i]) + $yBits[$i] ];
  }
  return $res;
}


