#!/usr/bin/python
#
#       Google maps for Navit     Python script v0.1.3
#
# Ported to Python and improved by
#    Alexander Chemeris <Alexander DOT Chemeris AT gmail DOT com>
#
# WARNING: This script provides only raster data to Navit, so
# it can't be used for routing. But it may be useful for other
# tasks or in the case you don't have vector maps for some region.
#
# To use this script, put it somewhere on the local file system and
# add one or more following entries to enabled mapset in navit.xml:
# 	<map type="textfile" data="/path/to/googlemaps.py\ type\ x\ y|"/>
# Here "type" is one of the following:
# * street - for street view
# * topo - for topographic view (streets + terrain)
# * sat - for satelite view
# Also set "x" and "y" to match Navit's drawing area size in pixels.
# This will allow script to shoose best available zoom level for
# downloaded maps. These values don't need to be exact, because
# zoom levels have a good step between them.
#
# Example:
# 	<map type="textfile" data="/usr/share/navit/googlemaps.py\ topo\ 1020\ 700|"/>
#
# NOTE: You need to have imlib2 support enabled in navit to be able
# display images.
#
# Developers info:
# In addition to manually specified arguments Navit also pass following
# arguments to the script:
# x_min  y_max  x_max  y_min orders_list
# x_* and y_* are just a "0xXXXX" strings, representing coordinates in
# Mercator projection used by Navit. Use mm(), mm_to_google() and
# google_to_mm() for converting passed coordinates to/from Google
# coordinate system (which is also Mercator).
#
# Changelog:
#
# version 0.1.3, 02 Dec 2008 21:54:42 +0300
#  * Create directory for tiles in does not exist.
#
# version 0.1.2, 02 Dec 2008 00:07:25 +0300
#  * Better zoom level matching.
#  * Better handling of 404/403 Google error codes.
#
# TODO:
#  * Download from different servers, or Google will return 403 errors.
#  * Check zoom level limits.
#  * Resize images on download. Now they're resized on every screen redraw
#    inside Navit, which makes it very slow on embedded/mobile devices.

import math
import sys
import os
import urllib

### Settings ###
tiles_path = "tiles"
download_images = True
### Setings end ###

def mm(val):
	val=int(val, 16)
	if val > 2**31:
		val -= 2**32
	return val;

def mm_to_google(scale, x, y):
	scale_e = float(256 * 2**scale)
	x = float(x)
	y = float(y)
	x_google = scale_e/2+x/6371000/math.pi*scale_e/2
	y_google = scale_e/2+0.25*(y/6371000)*2*-scale_e/math.pi
#	print >> sys.stderr, "mm_to_google", (scale, x, y,)
#	print >> sys.stderr, "	scale_e:", scale_e
#	print >> sys.stderr, "	mm(x, y):", (x, y,)
#	print >> sys.stderr, "	google(x, y):", (x_google, y_google,)
	return (int(x_google/256),int(y_google/256))

def google_to_mm(scale, x, y):
	scale_e = float(256 * 2**scale)
	x = float(x*256)
	y = float(y*256)
	mm_x = (x-scale_e/2)*6371000*math.pi/scale_e*2
	mm_y = (y-scale_e/2)/0.25*6371000/2/-scale_e*math.pi
	return (int(mm_x), int(mm_y))

#print >> sys.stderr
#print >> sys.stderr, "arguments:"
#print >> sys.stderr, "1: %s" % (sys.argv[1],)
#print >> sys.stderr, "2: %s" % (sys.argv[2],)
#print >> sys.stderr, "3: %s" % (sys.argv[3],)
#print >> sys.stderr, "4: %s" % (sys.argv[4],)
#print >> sys.stderr, "5: %s" % (sys.argv[5],)
#print >> sys.stderr, "6: %s" % (sys.argv[6],)
#print >> sys.stderr, "7: %s" % (sys.argv[7],)
#print >> sys.stderr, "8: %s" % (sys.argv[8],)


# Create directory for tiles if not present yet
if (not os.path.exists(tiles_path)):
    try:
        os.makedirs(tiles_path)
    except:
	pass
if (not os.path.exists(tiles_path)):
    print >> sys.stderr, "Can't create directory for tiles: ", tiles_path
    sys.exit()

# Parse command line arguments
map_type = sys.argv[1]
screen_width = int(sys.argv[2])
screen_height = int(sys.argv[3])
x_min = mm(sys.argv[4])
x_max = mm(sys.argv[6])
y_min = mm(sys.argv[7])
y_max = mm(sys.argv[5])

# Prepare for tiles download
zoom_levels = 17

dx=(x_max-x_min)/float(screen_width)
dy=(y_max-y_min)/float(screen_height)
d=(dx+dy)/4
scale=int(zoom_levels-math.log(d)/math.log(2))
if (scale < 2):
	scale=2

if (map_type == 'mt' and scale > 16):
	scale=16

(x1,y1)=mm_to_google(scale,x_min,y_max)
(x2,y2)=mm_to_google(scale,x_max,y_min)

zoom = zoom_levels - scale
scale_e = 2**scale

#print >> sys.stderr, "mm(x1, y1):", (x_min, y_max,)
#print >> sys.stderr, "mm(x2, y2):", (x_max, y_min,)
#print >> sys.stderr, "d(x, y):", (dx, dy,)
#print >> sys.stderr, "d:", d
#print >> sys.stderr, "scale:", scale
#print >> sys.stderr, "scale_e:", scale_e
#print >> sys.stderr, "google(x1, y1):", (x1, y1,)
#print >> sys.stderr, "google(x2, y2):", (x2, y2,)

# Download tiles
for y in range(y1, y2+1):
	for x in range(x1, x2+1):
		if (x >= 0 and y >= 0 and x < scale_e and y < scale_e):
			if (map_type == "street"):
				# Street maps
				path  = "mt?n=404&v=w2.99&x=%d&y=%d&zoom=%d" % (x, y, zoom,)
				host  = "mt.google.com"
				fname = "street-%d-%d-%d.png" % (zoom, x, y,)
			elif (map_type == "topo"):
				# Topo maps
				path  = "mt?n=404&v=w2p.99&x=%d&y=%d&zoom=%d" % (x, y, zoom,)
				host  = "mt.google.com"
				fname = "topo-%d-%d-%d.jpg" % (zoom, x, y,)
			elif (map_type == "sat"):
				# Satelite maps
				tmpx = x
				tmpy = y
				tile = "t"
				limit = scale_e
				for s in xrange(0, scale):
					limit = limit/2;
					if (tmpy < limit):
						if (tmpx < limit):
							tile += "q"
						else:
							tile += "r"
							tmpx -= limit
					else:
						if (tmpx < limit):
							tile += "t"
							tmpy -= limit
						else:
							tile += "s"
							tmpx -= limit
							tmpy -= limit
				path = "kh?n=404&v=24&t=" + tile
				host = "kh.google.com"
				fname = "sat-%s.jpg" % (tile,)
			else:
				print >> sys.stderr, "Unkonwn map type: ", map_type

			fname = tiles_path + "/" + fname
			if (download_images and not os.path.exists(fname)):
				url = 'http://%s/%s' % (host, path,)
#				os.system('wget "%s" -O %s' % (url, fname,))
				print >> sys.stderr, 'downloading "%s" from"%s"' % (fname, url,)
				def reporthook(*a): print >> sys.stderr, '.',
				(fname, header) = urllib.urlretrieve(url, fname, reporthook)
				if header.getmaintype() == 'text':
					# Google returned error. Remove file.
					os.remove(fname)
					print >> sys.stderr, "*** Error returned"
				print >> sys.stderr

			if (os.path.exists(fname)):
				(imgx1,imgy1)=google_to_mm(scale,x, y)
				(imgx2,imgy2)=google_to_mm(scale,x+1, y+1)
				print 'type=image label="%s"' % (fname,)
				print "0x%x 0x%x" % (imgx1, imgy1)
				print "0x%x 0x%x" % (imgx2, imgy1)
				print "0x%x 0x%x" % (imgx1, imgy2)
				print >> sys.stderr, 'show "%s"' % (fname,)
			else:
				if download_images:
					print >> sys.stderr, "Failed to load", path
				else:
					print >> sys.stderr, "File %s is not available." % (fname,)
					

