# -*- coding: utf-8 -*-
from pyGrid import geo
from ..     import SETUP
from .      import tms, mapset
import pickle, sys, os, re

if sys.version_info[:2] >= (3,0): xrange = range

class Googlemap(tms.Tms):

	name = property(lambda obj: "%s:%s:%s" % (obj.__module__.split(".")[-1].capitalize(), obj.maptype, obj.zoom), None, None, "")

	_url = {}
	_urlpath = os.path.join(SETUP["root"], "googlemap.%s.uri")

	def __init__(self, maptype = "roadmap", zoom = 1):
		if os.path.exists(Googlemap._urlpath % SETUP["googlemap language"]):
			dump = open(Googlemap._urlpath % SETUP["googlemap language"], "rb")
			Googlemap._url = pickle.load(dump)
			dump.close()

		tms.Tms.__init__(self, geo_class = geo.Proj(epsg = 3785), url = "http://maps.google.com/maps")
		self.configure(maptype = maptype, zoom = zoom)

	__setitem__ = lambda obj, item, value: obj.configure(**{item: value})
	def configure(self, **kw):
		if len(kw) == 0: return dict((k,v) for (k,v) in self.__dict__.items() if k in ["zoom", "maptype", "format"])
		self.__dict__.update(dict((k,v) for (k,v) in kw.items() if k in ["zoom", "maptype", "format"]))
		self._cachePatern = os.path.join(SETUP["cache"], "googlemap/%(maptype)s/%(zoom)d/%(i)d.%(j)d") #.jpg")
		self.minzoom = 1
		self.maxzoom = 15 if self.maptype == "terrain" else 19

		if self.zoom < self.minzoom: self.zoom = self.minzoom
		elif self.zoom > self.maxzoom: self.zoom = self.maxzoom
		self.nbcol = self.nbrow = 2**self.zoom

		if self.maptype not in Googlemap._url:
			handle = self.src.fetch("http://maps.google.com/maps?t=%s" % {
				"roadmap":   "m",
				"hybrid":    "h",
				"satellite": "k",
				"terrain":   "p"
			}[self.maptype], None, {'User-Agent': SETUP["user agent"]})

			if handle != -1:
				data = handle.read()
				pattern = re.compile('<div id=inlineTiles%s dir=ltr>' % ("" if self.maptype != "hybrid" else "Hybrid") + '<img src="https://([a-z]{2,4})[0-9].google.com/(.+?)&')
				match = pattern.search(bytes.decode(data))
				if match == None: raise Exception("cannot parse google maps data")
				Googlemap._url[self.maptype] = 'http://%s%%(server)s.google.com/%s' % tuple(match.groups()) + '&hl=%s'%SETUP["googlemap language"] + '&x=%(j)d&y=%(i)d&z=%(zoom)d'

				dump = open(Googlemap._urlpath % SETUP["googlemap language"], "wb")
				pickle.dump(Googlemap._url, dump, protocol = 0)
				dump.close()

		folder = os.path.abspath(os.path.dirname(self.tileCache(0,0)))
		if not os.path.exists(folder): os.makedirs(folder)

	def zoomIn(self, amount = None):
		if self.zoom < self.maxzoom: self.configure(zoom = self.zoom + (1 if amount == None else amount))
		else: return False
		return True

	def zoomOut(self, amount = None):
		if self.zoom > self.minzoom: self.configure(zoom = self.zoom + (-1 if amount == None else amount))
		else: return False
		return True

	def tileCache(self, row, col):
		return self._cachePatern % dict(self.__dict__, i=row, j=col)

	def tileUrl(self, row, col):
		if self.maptype in Googlemap._url:
			return Googlemap._url[self.maptype] % dict(self.__dict__, i=row, j=col, server = ["1","2","3"][self.src.accesscount%3])
		else:
			return ""

	def __getitem__(self, i, j = None):
		if j == None:
			i = len(self)+i if i < 0 else i
			i, j = i//self.nbcol, i%self.nbcol
		if i >= self.nbrow: raise IndexError("%d exceed row number (%d)"    % (i, self.nbrow))
		if j >= self.nbcol: raise IndexError("%d exceed column number (%d)" % (j, self.nbcol))
		return self.getTile(self.tileUrl(i, j), self.tileCache(i, j))

	__iter__  = lambda obj: iter(obj.subset(0, 0, obj.nbrow, obj.nbcol))
	def subset(self, i1, j1, i2, j2):
		if self.maptype not in Googlemap._url:
			yield iter([])
		else:
			tileUrl = lambda i, j, zoom = self.zoom, maptype = self.maptype, src = self.src: Googlemap._url[maptype] % {
				"zoom": zoom,
				"i": i,
				"j": j,
				"server": ["1","2","3"][src.accesscount%3]
			}
			tileCache = lambda i, j, zoom = self.zoom, maptype = self.maptype: self._cachePatern % {
				"maptype": maptype,
				"zoom": zoom,
				"i": i,
				"j": j,
				"format": "jpg"
			}
			for i in xrange(i1, i2):
				for j in xrange(j1, j2):
					if not mapset._continue(): break
					yield [(j-j1)*self.w, (i-i1)*self.h, mapset.TileGetter(self.getTile, tileUrl(i, j), tileCache(i, j))]

