### /obj/objgrid.py

from gui.imageimport import *
from conv.pixel	import ImageThreshold

inside_grid_pixel_w = 192

def gcd(m,n):
	while n != 0:
		t = m % n
		m = n
		n = t
	return abs(m)
	
def lcm(m,n):
	return (m * n) / gcd(m, n)
	
def app(float):
	if int(float) == float:
		return int(float)
	else:
		return int(float) + 1

def overlap(tuple1, tuple2):
	# tuple2 is determined by tuplet1
	l = list(tuple1 + tuple2)
	l.sort()
	t11, t12 = l.index(tuple1[0]), l.index(tuple1[1])
	if t11 > t12: t11, t12 = t12, t11
	if (t11, t12) <> (0, 1) and (t11, t12) <> (2,3):
		if l[1] <> l[2]:
			return (l[1], l[2])

class grid:
	def __init__(self):
		self.l = (1,1)
		
		self.data = None
		self.bond = None
		self.w, self.h = 0, 0
		
		self.chgrid      = []
		self.chgridxy    = []
		self.chgridalpha = []
		self.pil = None
		
	def setData(self,data,bond = None):
		self.data = data.copy()
		self.w = self.data.size[0]
		self.h = self.data.size[1]
		if bond <> None:
			self.bond = ImageThreshold(bond.copy().resize((self.w, self.h)))
		else:
			self.bond = Image.new('1',(self.w, self.h),255)
		self.makePIL()
	def makePIL(self):
		if self.w > inside_grid_pixel_w:
			self.pil = self.data.copy()
			for i in range(len(self.chgrid)):
				chw = \
					self.chgrid[i].w * self.chgrid[i].l[0] / self.chgrid[i].l[1]
				print chw
				chcrop = self.chgrid[i].pil.copy().resize((chw, self.chgrid[i].h))
				
				self.pil.paste(chcrop, ( \
					(self.chgridxy[i][0], \
					 self.chgridxy[i][1], \
					 self.chgridxy[i][0] + chw, \
					 self.chgridxy[i][1] + self.chgrid[i].h)))
		else:
			lm = app(float(inside_grid_pixel_w / self.w))
			self.pil = self.data.copy().resize((self.w * lm, self.h),Image.NEAREST)
			for i in range(len(self.chgrid)):
				chw = \
					self.chgrid[i].w * self.chgrid[i].l[0] / self.chgrid[i].l[1] 
				chcrop = self.chgrid[i].pil.copy().resize((chw * lm, self.chgrid[i].h),Image.NEAREST)
				
				self.pil.paste(chcrop, ( \
					(self.chgridxy[i][0] * lm, \
					 self.chgridxy[i][1], \
					 (self.chgridxy[i][0] + chw) * lm, \
					 self.chgridxy[i][1] + self.chgrid[i].h)))
			self.pil = self.pil.resize((self.w * lm, self.h * lm),Image.NEAREST)
	def blend(self, grid, alpha):		# same size
		# first change both grid's l
		newl = lcm(self.l[1],grid.l[1])
		self.resize((1,newl))
		grid.resize((1,newl))
		
		w = self.w
		h = self.h
		# blend data
		self.data = Image.blend(self.pil.resize((w,h)), grid.pil.resize((w,h)), alpha)
		self.bond = Image.blend(self.bond.resize((w,h)), grid.bond.resize((w,h)), alpha)
		
		# copy both chgrid
		if grid.chgrid <> []:
			self.chgrid      = self.chgrid + grid.chgrid
			self.chgridxy    = self.chgridxy + grid.chgridxy
			self.chgridalpha = self.chgridalpha + grid.chgridalpha
		
		self.makePIL()
		# self.pil.show()
	def resize(self,l):
		a = self.l[0] / l[0] * l[1] / self.l[1]
		self.l = l
		self.w = self.w * a
		self.data = self.data.resize((self.w, self.h))
		newbond = Image.new('1',(self.w, self.h),1)
		for i in range(self.bond.size[0]):
			for j in range(self.bond.size[1]):
				newbond.putpixel((i * a, j), self.bond.getpixel((i,j)))
		
		#for i in range(len(self.chgrid)):
		#	cx = self.chgridxy[i][0] * a
		#	cy = self.chgridxy[i][1]
		#	self.chgridxy[i] = (cx,cy)
		self.bond = newbond.copy()
		self.makePIL()
	def crop(self,box=(0,0,1,1)):
		# these coordinates are self-grid's scale
		x1, y1, x2, y2 = box
		
		newgrid = grid()
		newgrid.l = self.l
		newgrid.setData( \
			self.data.crop((x1, y1, x2, y2)),
			self.bond.crop((x1, y1, x2, y2)))
		for i in range(len(self.chgrid)):
			cx1, cy1 = self.chgridxy[i]
			cx2 = cx1 + self.chgrid[i].w * self.chgrid[i].l[0] / self.chgrid[i].l[1]
			cy2 = cy1 + self.chgrid[i].h
			
			ox = overlap((x1, x2), (cx1, cx2))
			oy = overlap((y1, y2), (cy1, cy2))
			
			if ox == None: continue
			if oy == None: continue
			cx1 = (ox[0] - self.chgridxy[i][0]) / \
				self.chgrid[i].l[0] * self.chgrid[i].l[1]
			cx2 = (ox[1] - self.chgridxy[i][0]) / \
				self.chgrid[i].l[0] * self.chgrid[i].l[1]
			cy1 = (oy[0] - self.chgridxy[i][1])
			cy2 = (oy[1] - self.chgridxy[i][1])
			cCrop = self.chgrid[i].crop((cx1, cy1, cx2, cy2))
			
			newgrid.chgrid.append(cCrop)
			newgrid.chgridxy.append((ox[0], oy[0]))
			newgrid.chgridalpha.append(1.0)
		return newgrid
	def addChgrid(self,chgrid,xy,alpha):
		if chgrid.l[0] <> 1:
			chgrid.resize((1,chgrid.l[1]))
		self.chgridxy.append(xy)
		self.chgrid.append(chgrid)
		self.chgridalpha.append(alpha)
	def makeTable(self):
		### relativity table
		self.makeCCT()
		self.putChgridIndex()
		
		#-- divide table and reconstruct chgrid
		self.newChgrid = []
		self.newChgridxy = []
		self.newChgridalpha = []
		self.divTable()
		
		self.chgrid = self.newChgrid
		self.chgridxy = self.newChgridxy
		self.chgridalpha = self.newChgridalpha
		
		#-- 
		self.makePIL()
	def divTable(self):				
		for j in range(self.table.h):
			i1 = None
			for i in range(self.table.w):
				if self.table.data[i][j] <> []:
					if i1 == None:	
						# start searching cropping area
						dataij = self.table.data[i][j]
						
						# j2 is an iterator, and 
						# j22 is a measure needed for deciding cropping area
						i1,j2,j22 = i,j,0
						
						# get j22 value
						j2 = self.setJ2(i,j,dataij)
						j22 = app((j2 - j) / 2.0)
					else:
						j2 = self.setJ2(i,j,dataij)
						if j2 < j + j22:
							# crop
							j2 = self.setJ2(i - 1,j,dataij)
							self.makeChgrid((i1, j, i - 1, j2))
							
							# start searching cropping area
							dataij = self.table.data[i][j]
							
							# j2 is an iterator, and 
							# j22 is a measure needed for deciding cropping area
							i1,j2,j22 = i,j,0
							
							# get j22 value
							j2 = self.setJ2(i,j,dataij)
							j22 = app((j2 - j) / 2.0)
					if i == self.table.w - 1:
						self.makeChgrid((i1, j, i, j2))
						i1 = None
						continue
				else:
					if i1 <> None:
						self.makeChgrid((i1, j, i - 1, j2))
						i1 = None
						continue		
	def setJ2(self,i,j,dataij):
		j2 = j
		while (self.table.data[i][j2] == dataij):
			j2 += 1
			if j2 >= self.table.h: break
		return j2 - 1

	def makeChgrid(self,box):
		# make new chgrid by cropping and blennding 
		# and delete chgrid from table
		x1, y1, x2, y2 = box[0], box[1], box[2] + 1, box[3] + 1
		
		chgrids = self.table.data[x1][y1]
		
		# make new Chgrid
		nChgrid = grid()
		nChgrid.l = self.l
		nChgrid.setData( \
			  self.data.crop((self.cxc[x1], self.cyc[y1], \
			  self.cxc[x2], self.cyc[y2])), \
			  self.bond.crop((self.cxc[x1], self.cyc[y1], \
			  self.cxc[x2], self.cyc[y2])))
		
		for i in chgrids:
			cx, cy = self.chgridxy[i]
			cCrop = self.chgrid[i].crop( \
			 ((self.cxc[x1] - cx) / self.chgrid[i].l[0] * self.chgrid[i].l[1], \
			  (self.cyc[y1] - cy) , \
			  (self.cxc[x2] - cx) / self.chgrid[i].l[0] * self.chgrid[i].l[1], \
			  (self.cyc[y2] - cy) ))
			nChgrid.blend(cCrop, self.chgridalpha[i])
		if len(chgrids) <> 0: 
			nChgrid.makeTable()
		
		self.newChgrid.append(nChgrid)
		self.newChgridxy.append((self.cxc[x1], self.cyc[y1]))
		self.newChgridalpha.append(1.0)
		# delete chgrid from table
		for i in range(x1, x2 - 1):
			for j in range(y1, y2 - 1):
				self.table.data[i][j] = []
	def makeCCT(self):
		#-- make cxc,cyc,table
		self.cxc, self.cyc = [0, self.w], [0, self.h]
		for i in range(len(self.chgrid)):
			fw = self.chgrid[i].w * self.chgrid[i].l[0] / self.chgrid[i].l[1]
			fh = self.chgrid[i].h
			cx = self.chgridxy[i][0]
			cy = self.chgridxy[i][1]
			
			for c in (cx, cx + fw):
				if c > self.w: c = self.w
				if c not in self.cxc:
					self.cxc.append(c)
			for c in (cy, cy + fh):
				if c > self.h: c = self.h
				if c not in self.cyc:
					self.cyc.append(c)
		self.cxc.sort()
		self.cyc.sort()
		print "cxc",self.cxc
		print "cyc",self.cyc
		self.table = rTable(self.cxc, self.cyc)
	def putChgridIndex(self):
		#-- put chgrid's index
		for i in range(len(self.chgrid)):
			fw = self.chgrid[i].w * self.chgrid[i].l[0] / self.chgrid[i].l[1]
			fh = self.chgrid[i].h
			cx = self.chgridxy[i][0]
			cy = self.chgridxy[i][1]
			
			if cx > self.w: continue
			if cy > self.h: continue
				
			if cx + fw > self.w: 
				mx = (cx, self.w)
			else:
				mx = (cx, cx + fw)
			if cy + fh > self.h: 
				my = (cy, self.h)
			else:
				my = (cy, cy + fh)
			
			mi = self.cxc.index(mx[0])
			while (mx[0] <= self.cxc[mi] < mx[1]):
				mj = self.cyc.index(my[0])
				while (my[0] <= self.cyc[mj] < my[1]):
					self.table.data[mi][mj].append(i)
					mj += 1
				mi += 1
		print self.table.data
	

class rTable:
	def __init__(self, cxc, cyc):
		self.w = len(cxc) - 1
		self.h = len(cyc) - 1
		
		self.data = []
		for i in range(self.w):
			self.data.append([])
			for j in range(self.h):
				self.data[i].append([])