#!/perl -w
# NAME: set-bucket.pl
# AIM: A perl rendering of the set_bucket() function in Simgear
# 04/03/2009 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
   my @tmpsp = split(/\\/,$pgmname);
   $pgmname = $tmpsp[-1];
}
my $outfile = "temp.$pgmname.txt";
open_log($outfile);
prt( "$0 ... Hello, World ...\n" );

# features
my $out_all = 0;

my $sample = '150.249900000008:-30: lon=150, lat=-30, x=0, y=0 ';
###my $sample = '-112:-47: lon=-112, lat=-47, x=0, y=0 ';
my $min_len = length($sample);
my $SG_BUCKET_SPAN = 0.125;
#/**
# * half of a standard SG_BUCKET_SPAN
# */
my $SG_HALF_BUCKET_SPAN = ( 0.5 * $SG_BUCKET_SPAN );
#/** For divide by zero avoidance, this will be close enough to zero */
my $SG_EPSILON = 0.0000001;

my ($lon, $lat, $x, $y, $path, $ind);

sub gen_index() {
   return (($lon + 180) << 14) + (($lat + 90) << 6) + ($y << 3) + $x;
}

#// return the horizontal tile span factor based on latitude
#static double sg_bucket_span( double l ) {
sub sg_bucket_span($) {
   my ($l) = shift;
    if ( $l >= 89.0 ) {
	return 360.0;
    } elsif ( $l >= 88.0 ) {
	return 8.0;
    } elsif ( $l >= 86.0 ) {
	return 4.0;
    } elsif ( $l >= 83.0 ) {
	return 2.0;
    } elsif ( $l >= 76.0 ) {
	return 1.0;
    } elsif ( $l >= 62.0 ) {
	return 0.5;
    } elsif ( $l >= 22.0 ) {
	return 0.25;
    } elsif ( $l >= -22.0 ) {
	return 0.125;
    } elsif ( $l >= -62.0 ) {
	return 0.25;
    } elsif ( $l >= -76.0 ) {
	return 0.5;
    } elsif ( $l >= -83.0 ) {
	return 1.0;
    } elsif ( $l >= -86.0 ) {
	return 2.0;
    } elsif ( $l >= -88.0 ) {
	return 4.0;
    } elsif ( $l >= -89.0 ) {
	return 8.0;
    } # else {
	return 360.0;
    #}
}

sub get_tile { # $alon, $alat
	my ($lon, $lat) = @_;
	my $tile = 'e';
	if ($lon < 0) {
		$tile = 'w';
		$lon = -$lon;
	}
	my $ilon = int($lon / 10) * 10;
	if ($ilon < 10) {
		$tile .= "00$ilon";
	} elsif ($ilon < 100) {
		$tile .= "0$ilon";
	} else {
		$tile .= "$ilon"
	}
	if ($lat < 0) {
		$tile .= 's';
		$lat = -$lat;
	} else {
		$tile .= 'n';
	}
	my $ilat = int($lat / 10) * 10;
	if ($ilat < 10) {
		$tile .= "0$ilat";
	} elsif ($ilon < 100) {
		$tile .= "$ilat";
	} else {
		$tile .= "$ilat"
	}
	return $tile;
}

#// Set the bucket params for the specified lat and lon
#void SGBucket::set_bucket( double dlon, double dlat ) {
sub set_bucket($$)
{
   my ($dlon, $dlat) = @_;
   # //
   # // latitude first
   # //
   # double span = sg_bucket_span( dlat );
   # double diff = dlon - (double)(int)dlon;
   my $span = sg_bucket_span( $dlat );
   my $diff = $dlon - int($dlon);
   #// cout << "diff = " << diff << "  span = " << span << endl;

   if ( ($dlon >= 0) || (abs($diff) < $SG_EPSILON) ) {
      $lon = int($dlon);
   } else {
      $lon = int($dlon - 1);
   }

   #// find subdivision or super lon if needed
   if ( $span < $SG_EPSILON ) {
      #// polar cap
      $lon = 0;
      $x = 0;

   } elsif ( $span <= 1.0 ) {
      $x = int(($dlon - $lon) / $span);
   } else {
      if ( ($dlon >= 0) || (abs($diff) < $SG_EPSILON) ) {
         $lon = int( int($lon / $span) * $span);
	   } else {
	      #// cout << " lon = " << lon 
	      #//  << "  tmp = " << (int)((lon-1) / span) << endl;
	      $lon = int( int(($lon + 1) / $span) * $span - $span);
	      if ( $lon < -180 ) {
            $lon = -180;
	      }
	   }
   	$x = 0;
   }
   # //
   # // then latitude
   # //
   $diff = $dlat - int($dlat);

   if ( ($dlat >= 0) || (abs($diff) < $SG_EPSILON) ) {
      $lat = int($dlat);
   } else {
      $lat = int($dlat - 1);
   }
   $y = int(($dlat - $lat) * 8);
}

#// Build the path name for this bucket
#string SGBucket::gen_base_path() const {
sub gen_base_path() {
   #// long int index;
   my ($top_lon, $top_lat, $main_lon, $main_lat);
   my ($hem, $pole);
   # char raw_path[256];

   $top_lon = $lon / 10;
   $main_lon = $lon;
   if ( ($lon < 0) && ($top_lon * 10 != $lon) ) {
      $top_lon -= 1;
   }
   $top_lon *= 10;
   if ( $top_lon >= 0 ) {
      $hem = 'e';
   } else {
   	$hem = 'w';
      $top_lon *= -1;
   }
   if ( $main_lon < 0 ) {
      $main_lon *= -1;
   }
    
   $top_lat = $lat / 10;
   $main_lat = $lat;
   if ( ($lat < 0) && ($top_lat * 10 != $lat) ) {
      $top_lat -= 1;
   }
   $top_lat *= 10;
   if ( $top_lat >= 0 ) {
      $pole = 'n';
   } else {
       $pole = 's';
       $top_lat *= -1;
   }
   if ( $main_lat < 0 ) {
	   $main_lat *= -1;
   }

   return sprintf("$hem%03d$pole%02d/$hem%03d$pole%02d",
	    $top_lon, $top_lat, 
	    $main_lon, $main_lat);

   # SGPath path( raw_path );
   # return path.str();
}

sub show_bucket($$$) {
   my ($ii, $jj, $disp) = @_;
   set_bucket( $ii, $jj );
   $path = gen_base_path();
   my $msg = "$ii:$jj: lon=$lon, lat=$lat, x=$x, y=$y";
   $msg .= ' ' while (length($msg) < $min_len);
   $ind = gen_index();
   prt( "$msg [$path] $ind\n" ) if ($disp);
}

#      0 KSFO San Francisco Intl (37.6208607739872,-122.381074803838) tile=w120n30
show_bucket(-122.381074803838, 37.6208607739872, 1);

my $cnt = 0;
my $max = 8;
my $test_lon = 150.0;
my $test_lat = -30;
my ($last_lon, $last_lat, $next_lon, $next_lat);
prt( "$cnt: " );
show_bucket($test_lon, $test_lat, 1);
my $test_path = $path;
my $test_ind = $ind;
my ($ti, $tj);
my $new_path = $path;
my $new_ind = $ind;
$last_lon = $test_lon;
$last_lat = $test_lat;
for ($ti = $test_lon; ; $ti += 0.0001) {
   $tj = $test_lat;
   show_bucket( $ti, $tj, 0 );
   if (($new_path ne $path)||($new_ind != $ind)) {
      $new_path = $path;
      $new_ind = $ind;
      $cnt++;
      prt( "$cnt: " );
      show_bucket( $last_lon, $last_lat, 1 );
      if ($cnt > $max) {
         last;
      }
   }
   $last_lon = $ti;
   $last_lat = $tj;
}

prt( "\nAnd back wards...\n" );
$next_lon = $test_lon;
$next_lat = $test_lat;
$cnt = 0;
prt( "$cnt: " );
show_bucket($test_lon, $test_lat, 1);
$new_path = $path;
$new_ind = $ind;
$last_lon = $test_lon;
$last_lat = $test_lat;
for ($ti = $test_lon; ; $ti -= 0.0001) {
   show_bucket( $ti, $tj, 0 );
   if (($new_path ne $path)||($new_ind != $ind)) {
      $new_path = $path;
      $new_ind = $ind;
      $cnt++;
      prt( "$cnt: " );
      show_bucket( $next_lon, $next_lat, 1 );
      if ($cnt > $max) {
         last;
      }
   }
   $next_lon = $ti;
   $next_lat = $tj;
}

if ($out_all) {
   for (my $i = -180; $i <= 180; $i++) {
      for (my $j = -90; $j <= 90; $j++) {
         show_bucket( $i, $j, 1 );
      }
   }
}

close_log($outfile,1);
exit(0);

# eof
