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

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


class Custom(tms.Tms):

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

	def __init__(self, familly, maptype, zoom = 1):
		search = [dsc for dsc in Custom.descriptions if dsc["maptype"] == maptype and dsc["familly"] == familly]
		if len(search) > 0:
			dsc = search[-1]
			tms.Tms.__init__(self, geo_class = geo.Proj(epsg = dsc["epsg"]), url = dsc["url"])
			self.configure(**dict(dsc, zoom = zoom))
		else:
			raise Exception

	__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", "familly"])
		self.__dict__.update(dict((k,v) for (k,v) in kw.items() if k in ["familly", "maptype", "bottom_left", "top_right", "type", "tile_url", "zoom", "minzoom", "maxzoom", "server_loop"]))

		self._cachePatern = bytes(os.path.join(SETUP["cache"],"custom/%(familly)s/%(maptype)s/%(zoom)d/%(i)d.%(j)d")) #.jpg") )
		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

		# limites
		if self.bottom_left != self.top_right:
			self.sub_rowShift, self.sub_colShift = [int(math.floor(e)) for e in self.ll2rc(*self.bottom_left)]
			r2, c2 = [int(math.ceil(e)) for e in self.ll2rc(*self.top_right)]
			self.sub_nbrow = abs(r2 - self.sub_rowShift)
			self.sub_nbcol = abs(c2 - self.sub_colShift)

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

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

	def tileUrl(self, row, col):
		row = row if self.type in ["XY", "Q"] else (2**self.zoom - 1 - row)
		return self.tile_url % dict(self.__dict__, i=row, j=col, q=self.ij2Q(row, col), server = self.server_loop[self.src.accesscount%len(self.server_loop)])

	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 __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))
		if self.sub_nbrow != 0: i = 2**self.zoom//2 - self.sub_rowShift - self.rows + i
		if self.sub_nbcol != 0: j = self.sub_colShift + 2**self.zoom//2 + j
		return self.getTile(self.tileUrl(i, j), self.tileCache(i, j))

	__iter__  = lambda obj: iter(obj.subset(0, 0, obj.rows, obj.columns))
	def subset(self, i1, j1, i2, j2):
		tileUrl = lambda i, j, sub = bool(self.sub_nbrow), rows = self.rows, cshift = self.sub_colShift, rshift = self.sub_rowShift, zoom = self.zoom, typ = self.type, src = self.src: self.tile_url % {
			"zoom": zoom,
			"i": (2**zoom//2 - rshift - rows + i) if sub else i if typ in ["XY", "Q"] else (2**zoom-1) - ((2**zoom//2 - rshift - rows + i) if sub else i),
			"j": cshift + 2**zoom//2 + j if sub else j,
			"q": self.ij2Q(i, j),
			"server": self.server_loop[src.accesscount%len(self.server_loop)]
		}
		tileCache = lambda i, j, sub = bool(self.sub_nbrow), rows = self.rows, cshift = self.sub_colShift, rshift = self.sub_rowShift, zoom = self.zoom, maptype = self.maptype, familly = self.familly: self._cachePatern % {
			"maptype": maptype,
			"zoom": zoom,
			"i": (2**zoom//2 - rshift - rows + i) if sub else i,
			"j": cshift + 2**zoom//2 + j if sub else j,
			"familly":familly,
			"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))]
