<?php
//------------------------------------------------------------------------------
// map-o-net.com image drawing code
//
// version 1.2 - 2007-05-31
//
// by Hourann Bosci <http://hourann.com>
// with thanks to John Prevost and Anders Kaseorg for bug reports,
// Thiadmer Riemersma for the Hilbert-drawing algorithm used here,
// and Randall Munroe of xkcd.com for developing the map!
//
// This code may be redistributed and/or modified under the terms of
// the GNU General Public License, version 2. For details, visit
// http://www.gnu.org/copyleft/gpl.html
//
//------------------------------------------------------------------------------
//
// Randall's map drawing is 672 pixels wide by (672 + big last row = 680) high
// with 16 columns and 16 rows.
//
// Horizontal line y pixel values: 106, 144, 191, 236, 276, 318, 359, 402,
//				   449, 486, 527, 569, 613, 654, 700, 738, 780
//
// The top left corner of the map is at pixel position (34, 104)
//
//------------------------------------------------------------------------------
// Code-modifications (functionalized map drawing etc...) by Nindra


$currentValue = 0;
$rowNum = 0;

$posX = 34;
$posY = 104;
$targetValue = 0;

$heightSlash8 = array( 42, 47, 46, 40, 42, 41, 43, 47, 37, 41, 42, 44, 41, 46, 38, 42 );
$widthSlash8 = 42;
$widthSlash16 = $widthSlash8 / 16;

$levelDirections = array(
        'LEFT' => array( 'UP', 'RIGHT', 'LEFT', 'DOWN', 'LEFT', 'LEFT', 'DOWN' ),
        'RIGHT' => array( 'DOWN', 'LEFT', 'RIGHT', 'UP', 'RIGHT', 'RIGHT', 'UP' ),
        'UP' => array( 'LEFT', 'DOWN', 'UP', 'RIGHT', 'UP', 'UP', 'RIGHT' ),
        'DOWN' => array( 'RIGHT', 'UP', 'DOWN', 'LEFT', 'DOWN', 'DOWN', 'LEFT' )
);

function mapdraw($ip, $label)
{
    // The Hilbert curve, represented by a recursive set of directions.
    // See hilbert() below, and http://www.compuphase.com/hilbert.htm

    //------------------------------------------------------------------------------
    // Break the IP into octets
    
    $octets = explode( ".", $ip );
    if ( count( $octets ) != 4 ) {
	die( "That IP address doesn't seem to be valid! Hit Back and try again." );
    }

    foreach ( $octets as $number ) {
	if ( !ctype_digit( $number ) || $number > 255 ) {
		die( "That IP address doesn't seem to be valid! Hit Back and try again." );
	}
    }
    
    //------------------------------------------------------------------------------
    // Step through the Hilbert curve
    // Global variables (yeah, I know) will keep track of how far we've travelled
    // and our current position
    global $currentValue, $rowNum, $posX, $posY, $targetValue;
    $currentValue = 0;
    $rowNum = 0;
    
    $posX = 34;
    $posY = 104;
    
    // This script is only concerned with the first two octets -- anything
    // smaller would be a change of less than two pixels.
    $targetValue = 256 * $octets[0] + $octets[1];
    
    // Recursion starts ... now.
    hilbert( 256 );
    
    
    //------------------------------------------------------------------------------
    // JPEG-drawing time!
    
    $posX = round( $posX );
    $posY = round( $posY );
    
    $textPosX = $posX + 5;
    $textPosY = $posY + 11;
    
    $map = imagecreatefrompng( 'afcmap.png' );
    // To give "area of certainty" / error bounds
    $errorColour = imagecolorallocate( $map, 218, 218, 255 );
    imageellipse( $map, $posX, $posY, 20, 20, $errorColour );
    
    // Find out how big our text is before we work with it.
    $sizeOfText = imageftbbox ( 9, 0, 'DejaVuSans.ttf', $label );
    
    $rect1 = $textPosX - 1;
    $rect2 = $posY;
    $rect3 = $textPosX + $sizeOfText[2] + 1;
    $rect4 = $posY + 13;
    
    // Switch text position if it's too far to the right.
    if ( $textPosX + $sizeOfText[4] > 700 ) {
            $textPosX = $posX - $sizeOfText[4] - 5;
            $rect1 = $textPosX - 1;
            $rect3 = $posX - 4;
    }
    
    // Draw a background for the label ...
    $white = imagecolorallocate( $map, 255, 255, 255 );
    imagefilledrectangle( $map, $rect1, $rect2, $rect3, $rect4, $white );
    
    // ... then the text itself ...
    $textColour = imagecolorallocate( $map, 96, 0, 0 );
    imagefttext( $map, 9, 0, $textPosX, $textPosY, $textColour, 'DejaVuSans.ttf', $label );
    
    // ... and the location dot.
    $dotColour = imagecolorallocate( $map, 204, 0, 0 );
    imagefilledellipse( $map, $posX, $posY, 4, 4, $dotColour );
    
    // For "homing beacon" effect.
    imageellipse( $map, $posX, $posY, 8, 8, $dotColour );
    
    // Finally, save the generated map to a JPG (that is sent to user) and a PNG (our "database")
    imagepng($map, 'afcmap.png');
    imagejpeg($map, 'afcmap.jpg');
    imagedestroy( $map );
}

//------------------------------------------------------------------------------


// Step one unit in the given direction.
// This function updates the global tracking variables so there's a
// running tally of our current position, and uses that to determine
// how many pixels to move at each step.
function move( $direction ) {
	global $heightSlash8, $widthSlash16, $rowNum;
	global $currentValue, $targetValue;
	global $posX, $posY;

	if ( $currentValue == $targetValue ) {
		// We're already at our target (which was probably 0)
		return true;
	}

	// Increment our "how many steps?" counter ...
	$currentValue ++;

	// ... and figure out where we're moving.
	if ( $direction == 'UP' ) {
		$rowNum --;
		// Up means subtract previous row height
		$posY = $posY - $heightSlash8[ floor( $rowNum / 16 ) ] / 16;
	} elseif ( $direction == 'DOWN' ) {
		$rowNum ++;
		// Down means add current row height
		$posY = $posY + $heightSlash8[ floor( $rowNum / 16 ) ] / 16;
	} elseif ( $direction == 'LEFT' ) {
		$posX = $posX - $widthSlash16;
	} elseif ( $direction == 'RIGHT' ) {
		$posX = $posX + $widthSlash16;
	}

	// Have we hit the target?
	if ( $currentValue == $targetValue ) {
		return true;
	}

	return false;
}


// Recursively step through the Hilbert curve of the given level
// by starting with the given direction.
// Each cycle has four recursive calls to hilbert()
// the first three of which are followed calls to move()
// ... so for the first six, loop through the array of
// directions with both functions, and make the last call
// to hilbert() separately.
// If $level == 1 we need to omit the calls to hilbert()
// and stop recursing.
function hilbert( $level, $direction='UP' ) {
	global $levelDirections;

	// At the top of this script, the Hilbert curve is
	// defined by sets of directions, each pair of which
	// is used to call hilbert() and move() again.
	$dirs = $levelDirections[ $direction ];

	for ( $i = 0; $i < 6; $i += 2 ) {

		if ( $level != 1 ) {
			$hbResult = hilbert( $level-1, $dirs[ $i ] );
			if ( $hbResult ) {
				return $hbResult;
			}
		}

		$moveResult = move( $dirs[ $i+1 ] );
		if ( $moveResult ) {
			// A non-false return from either function means
			// we've found our target, so we can break out
			// of the recursion.
			return $moveResult;
		}

	}

	if ( $level != 1 ) {
		$hbResult = hilbert( $level-1, $dirs[ 6 ] );
		if ( $hbResult ) {
			return $hbResult;
		}
	}

	return false;
}


?>