#!/usr/bin/perl
# geohash.pl - brute forces geohash data to try to find a 'stay at home' location

# these are coordinates
use Digest::MD5 qw(md5_hex);
use List::Util qw(min max);
my @lat=(53.47,53.48);
my @lng=(-2.92,-2.93);
my @dow=(700000,1500000); # 100x more
my @date=(2008,6,1);
my $days=31; # do one month
$debug=0;
($min[0],$max[0])=&todecimal(@lat);
($min[1],$max[1])=&todecimal(@lng);
print join ("\n", @lat, @lng, @min, @max)."\n" if $debug>0;

for ($dayloop=0;$dayloop<=$days;$dayloop=$dayloop+1) {
  for ($dowloop=@dow[0];$dowloop<=@dow[1];$dowloop=$dowloop+1) {
    $dowvalue=sprintf("%04d\-%02d\-%02d\-%.2f",@date,$dowloop/100);
    print $dowvalue if ($debug>1);
    &checkhit($dowvalue)
  };
  @date=&onemoreday(@date);
}

END;

sub todecimal {
  @test=@_;
  # 1) check if crosses zero, if so, change to 0..max abs value.
  if (($test[0]<0 and $test[1]>0) or ($test[0]>0 and $test[1]<0)) {@test=(0,abs(max(@test)))};
  # 2) check to see if >1, if so, RETURN 0..1
  if (max(@test)-min(@test) > 1) {return (0,1)};
  # 3) take absolute and return integer part
  $test[0]=abs($test[0]); $test[1]=abs($test[1]);
  return ($test[0]-int($test[0]), $test[1]-int($test[1]));

}

sub onemoreday {
@date=@_;

if ($date[2]==28 and $date[1]==2) {
  # oh gods, is it a leap year? TODO - actually implement it properly, with 100 and 400 year rule
  if (int($date[0]/4)*4==$date[0]) {return ($date[0],2,29)} else {return ($date[0],3,1)};
  }

if ($date[2]<29) {return ($date[0],$date[1],$date[2]+1)};

if ($date[2]==29) {
  if ($date[1]==2) {return ($date[0],3,1)}
    else {return ($date[0],$date[1],30)}};


if ($date[2]==30) {
  if ($date[1]==1 or $date[1]==3 or $date[1]==5 or $date[1]=7 or $date[1]=8
      or $date[1]=10 or $date[1]=12)
    {return ($date[0],$date[1],31)} else {return ($date[0],$date[1]+1,1)}};
    
if ($date[2]==31) {
  if ($date[1]==12) {return ($date[0]+1,1,1)} else
    {return ($date[0],$date[1]+1,1)};}
  
die "Bad date.";
}

  

sub checkhit {
$attempt=@_[0];
print "Attempting ".$attempt."\n" if ($debug >2);
$md5long=md5_hex($attempt);
@md5hex=(substr($md5long,0,16),substr($md5long,16,16));
print " MD5: ".join (',',@md5hex),"\n" if ($debug>2);

# divide. Code lovingly stolen from http://irc.peeron.com/xkcd/map/xkcd.js
@hash=(0,0);
for ($i=1; $i<= 16; $i++) {
  @hash[0] += hex(substr($md5hex[0],16-$i,1));
  @hash[1] += hex(substr($md5hex[1],16-$i,1));
  @hash[0] /= 16;
  @hash[1] /= 16;
  print join (',',@hash),"\n" if $debug>1;  
}
  print " DEC: ".join (',',@hash),"\n" if ($debug>2);  

# check if we have a hit.
  if (@hash[0]<@max[0] and @hash[0]>@min[0]
  and @hash[1]<@max[1] and @hash[1]>@min[1])
    {print "MATCH FOUND AT $attempt! (".join(',',@hash).")\n";
     $success=1}
  else {$success=0};
  return $success;
};  
  
  
