<?php

//Check for parameter availability
if (!isset($_GET['t'])||!isset($_GET['lt'])||!isset($_GET['ln'])||!isset($_GET['z'])||!isset($_GET['w'])||!isset($_GET['h'])||!isset($_GET['e'])) {
	//Check for uri presence
	if (empty($_SERVER['REQUEST_URI'])) {
		throw new Exception('No request uri');
	}
	//Check for script name in request uri
	if (($pos = strpos($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME'])) !== false) {
		$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $pos).substr($_SERVER['REQUEST_URI'], $pos+strlen($_SERVER['SCRIPT_NAME']));
	}
	//Check uri matching
	if (!preg_match('!^/(?<t>osm|osmar|cycle|mapnik)/(?<lt>-?[0-9\.]+),(?<ln>-?[0-9\.]+),(?<z>[0-9]+)/(?<w>[0-9]+)x(?<h>[0-9]+)\.(?<e>gif|jpe?g|png)$!', $_SERVER['REQUEST_URI'], $_GET)) {
		throw new Exception('No request match');
	}
	//Cleanup match array
	unset($_GET[0], $_GET[1], $_GET[2], $_GET[3], $_GET[4], $_GET[5], $_GET[6], $_GET[7]);
}

//Check latitude value
if (abs($lt = floatval($_GET['lt'])) > 90) {
	throw new Exception('Invalid latitude');
}

//Check longitude value
if (abs($ln = floatval($_GET['ln'])) > 180) {
	throw new Exception('Invalid longitude');
}

//Check zoom value
if (($z = abs(intval($_GET['z']))) > 20) {
	throw new Exception('Invalid zoom');
}

//Check width value
if (($w = abs(intval($_GET['w']))) > 1024) {
	throw new Exception('Invalid width');
}

//Check height value
if (($h = abs(intval($_GET['h']))) > 1024) {
	throw new Exception('Invalid height');
}

//Check type value
if (($t = ($_GET['t']=='mapnik'?'osm':$_GET['t'])) != 'osm' && $t != 'osmar' && $t != 'cycle') {
	throw new Exception('Invalid extension');
}

//Check extension value
if (($e = ($_GET['e']=='jpeg'?'jpg':$_GET['e'])) != 'gif' && $e != 'jpg' && $e != 'png') {
	throw new Exception('Invalid extension');
}

//Check imagick presence
if (!class_exists('Imagick')) {
	throw new Exception('No imagick class');
}

class Osm {
	//Set the tile size
	const tz = 256;

	//The imagick instance
	private $im;

	//Set tile sources
	//XXX: see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
	protected $uris = [
		'osm' => 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png',
		'osmar' => 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{Z}/{X}/{Y}.png',
		'cycle' => 'http://a.tile.opencyclemap.org/cycle/{Z}/{X}/{Y}.png',
	];

	function __construct($t, $lt, $ln, $z, $w, $h, $e) {
		//Get tile xy
		$tx = floor($cx = $this->lnToTx($ln, $z));
		$ty = floor($cy = $this->ltToTy($lt, $z));

		//Calculate start xy
		$sx = floor(($tx * self::tz - $w) / self::tz);
		$sy = floor(($ty * self::tz - $h) / self::tz);

		//Calculate end xy
		$ex = floor(($tx * self::tz + $w) / self::tz);
		$ey = floor(($ty * self::tz + $h) / self::tz);

		//Create the base image
		$this->im = new Imagick();
		$this->im->newImage($w, $h, new ImagickPixel('white'), $e);

		for($x = $sx; $x <= $ex; $x++) {
			for($y = $sy; $y <= $ey; $y++) {
				//Set file
				$file = '../cache/'.$z.'/'.$x.'/'.$y.'.png';
				//Create cache directory
				if (!is_dir($dir = dirname($file))) {
					mkdir($dir, 0777, true);
				}
				//Fetch file in cache
				if (!file_exists($file)) {
					$url = str_replace(['{Z}', '{X}', '{Y}'], [$z, $x, $y], $this->uris[$t]);
					file_put_contents($dir.'/'.$y.'.png', file_get_contents($url));
				}

				//Set dest x to
                		#$dx = ($x - floor($this->centerX - ($this->width / $this->tileSize) / 2)) * $this->tileSize + floor((floor($this->centerX) - $this->centerX) * $this->tileSize);
				$dx = ($x - floor($cx - ($w / self::tz) / 2)) * self::tz + floor(($tx - $cx) * self::tz);
				#$destY = ($y - $startY) * $this->tileSize + $this->offsetY;
				$dy = ($y - floor($cy - ($h / self::tz) / 2)) * self::tz + floor(($ty - $cy) * self::tz);

				//Create tile image
				$tm = new Imagick($file);
				//Add it at destination
				$this->im->compositeImage($tm, imagick::COMPOSITE_COPY, $dx, $dy);
			}
		}
		//Add circle
		//XXX: see https://www.php.net/manual/fr/imagick.examples-1.php#example-3916
		$draw = new ImagickDraw();
		$draw->setFillColor('#cff');
		$draw->setStrokeColor('#00c3f9');
		$draw->setStrokeWidth(2);
		$draw->circle($w/2 - 5, $h/2 - 5, $w/2 + 5, $h/2 + 5);
		$this->im->drawImage($draw);
		header('Content-Type: image/'.$e);
		echo $this->im;
	}

	/**
	 * Convert longitude to tile x number
	 *
	 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_5
	 *
	 * @param $ln The longitude
	 * @param $z The zoom
	 *
	 * @return The tile x
	 */
	public function lnToTx($ln, $z) {
		return (($ln + 180) / 360) * pow(2, $z);
	}

	/**
	 * Convert latitude to tile y number
	 *
	 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_5
	 *
	 * @param $lt The latitude
	 * @param $z The zoom
	 *
	 * @return The tile y
	 */
	public function ltToTy($lt, $z) {
		return (1 - log(tan(deg2rad($lt)) + 1 / cos(deg2rad($lt))) / pi()) / 2 * pow(2, $z);
	}

	/**
	 * Convert tile x to longitude
	 *
	 * @param $tx The tile x
	 * @param $z The zoom
	 *
	 * @return $ln The longitude
	 */
	public function txToLn($tx, $z) {
		return $tx / pow(2, $z) * 360.0 - 180.0;
	}

	/**
	 * Convert tile y to latitude
	 *
	 * @param $ty The tile y
	 * @param $z The zoom
	 *
	 * @return $lt The latitude
	 */
	public function tyToLt($ty, $z) {
		return rad2deg(atan(sinh(pi() * (1 - 2 * $ty / pow(2, $z)))));
	}

}


//Match url
header('Content-Type: text/plain');

$o = new Osm($t, $lt, $ln, $z, $w, $h, $e);

		/*
		//Get center x
		$cx = $this->lnToTile($lt, $z);

		//Get center y
		$cy = $this->ltToTile($ln, $z);

		//Get offset x
		$ox = floor((floor($cx) - $cx) * $tz);
		//Get offset y
		$oy = floor((floor($cy) - $cy) * $tz);

		//TODO: see this fucking computing
		$sx = floor($cx - ($w / $tz) / 2);
		$sy = floor($cy - ($h / $tz) / 2);
		$ex = ceil($cx + ($w / $tz) / 2);
		$ey = ceil($cy + ($h / $tz) / 2);

		$ox = -floor(($cx - floor($cx)) * $tz);
		$oy = -floor(($cy - floor($cy)) * $tz);

		$ox += floor($w / 2);
		$oy += floor($h / 2);
		$ox += floor($sx - floor($cx)) * $tz;
		$oy += floor($sy - floor($cy)) * $tz;
		 */

		#$ox = floor($tx - floor($tx)) * $tz;
		#$oy = floor($ty - floor($ty)) * $tz;

		#var_dump($sx);
		#var_dump($cx);

#		var_dump($sx);
#		var_dump($tx);
#		var_dump($ex);
#		var_dump($sy);
#		var_dump($ty);
#		var_dump($ey);

		#$im->newImage($w, $h, new ImagickPixel('transparent'), $e);

		#for($x = $tx; $x <= $tx; $x++) {
			#for($y = $ty; $y <= $ty; $y++) {
#				$my = new Imagick($file);
				#$my->newImage(5, 5, new ImagickPixel('black'), $e);

#$this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize);
#$this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize);
#$this->offsetX += floor($this->width / 2);
#$this->offsetY += floor($this->height / 2);
#$this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize;
#$this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize;
#$destX = ($x - $startX) * $this->tileSize + $this->offsetX;
#$destY = ($y - $startY) * $this->tileSize + $this->offsetY;
#        $this->centerX = $this->lonToTile($this->lon, $this->zoom);
#        $this->centerY = $this->latToTile($this->lat, $this->zoom);
#        $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize);
#        $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize);

#				$im->compositeImage($my, imagick::COMPOSITE_COPY, $dx, $dy);
#				#floor($w/2)-floor($tz/2), floor($h/2)-floor($tz/2));
#				header('Content-Type: image/'.$e);
#				echo $im;
#				exit;
#
#				$dx = ($x - $sx) * $tz + floor($w / 2);
#				$dy = ($y - $sy) * $tz + floor($h / 2);
#
#				var_dump($dx);
#				var_dump($dy);
#				var_dump(floor($w / 2) - floor(($tx - floor($tx))));
#				exit;
#
				#var_dump($url);
#				exit;
#				$tm = new Imagick($url);
#				$im->compositeImage($tm, imagick::COMPOSITE_OVER, $dx, $dy);