import pygame,mapgen,random
from pygame.locals import *
from settings import *
from numpy import random as rn
import circle
import numpy

class Tiles():
	def __init__(self, screenSize, physics, tMap = None, type = "map",encType = "none",encXY = (0,0),mapTiles = None,artifact= (0,0), flufftype = None):
		self.type = type
		self.artifact = artifact
		self.flufftype = flufftype
		if self.type == "map":
			self.w = settings_mapgen['xsize']
			self.h = settings_mapgen['ysize']
			self.light = circle.sun(self.w,self.h)
		elif self.type == "encounter":
			self.w = settings_encounters['xsize']
			self.h = settings_encounters['ysize']
			self.encType = encType
			self.encXY = encXY
			self.mapTiles = mapTiles
		self.tSurf = pygame.Surface((self.w * 32, self.h * 32), pygame.SRCALPHA, 32).convert_alpha()

		self.mapProb = settings_mapgen['prob']
		self.mapIts = settings_mapgen['its']

		self.tSize = settings_tiles['tilesize']
		if self.type == "map":
			self.tSet = pygame.image.load(settings_tiles['tileset']).convert_alpha()
		else:
			self.tSet = pygame.image.load(settings_tiles['enctileset']).convert_alpha()

		if self.type == "map":
			self.tSetPlayer = pygame.image.load(settings_tiles['playersprite'])
		else:
			self.tSetPlayer = pygame.image.load(settings_tiles['eplayersprite'])

		self.x,self.y = 0,0
		self.screenSize = screenSize
		self.physics = physics

		self.mountainTops = []

		if tMap == None:
			self.tMap = mapgen.segment_map(mapgen.nm(self.w, self.h, self.mapProb, self.mapIts))
			self.tMap = numpy.rot90(numpy.rot90(numpy.rot90(self.tMap)))
		else:
			self.tMap = tMap


		self.createSurface()

	def createSurface(self):
		dict = {
			"40110":  0,"40111":  1,"40011":  2,"40100":  3,"40101":  4,"40001":  5,"20010":  6,"20110":  7,"20111":  8,"20011":  9,
			"41110": 10,"41111": 11,"41011": 12,"40010": 13,"XXXXX": 14,"XXXXX": 15,"21010": 16,"21110": 17,"21111": 18,"21011": 19,
			"41100": 20,"41101": 21,"41001": 22,"41010": 23,"XXXXX": 24,"XXXXX": 25,"21000": 26,"21100": 27,"21101": 28,"21001": 29,
			"60100": 30,"60101": 31,"60001": 32,"41000": 33,"XXXXX": 34,"01111": 35,"XXXXX": 36,"20100": 37,"20101": 38,"20001": 39,
			"60110": 40,"60111": 41,"60011": 42,"60010": 43,"XXXXX": 44,"XXXXX": 45,"XXXXX": 46,"XXXXX": 47,"XXXXX": 48,"XXXXX": 49,
			"61110": 50,"61111": 51,"61011": 52,"61010": 53,"XXXXX": 54,"XXXXX": 55,"XXXXX": 56,"XXXXX": 57,"XXXXX": 58,"XXXXX": 59,
			"61100": 60,"61101": 61,"61001": 62,"61000": 63}
		for x, row in enumerate(self.tMap):
			for y, value in enumerate(row):
				baseStr = ""
				if self.type == "map":
					if value != 0: baseStr += str(value-2)
					else: baseStr += "0"
				elif self.type == "encounter":
					baseStr += self.encFixTileBase(x,y)
				baseStr += "1111"
				base = self.getTile(dict[baseStr])
				self.tSurf.blit(base,(x*self.tSize,y*self.tSize))
				rot = self.physics.gravity_orientation
				if self.type == "encounter" : 
					border = self.getTile(self.getTileBorder(x,y,dict,rot))
					border = pygame.transform.rotate(border,(90*(rot)))
					#print rot,self.physics.gravity_orientation
				else: 
					border = self.getTile(self.getTileBorder(x,y,dict))

				self.tSurf.blit(border,(x*self.tSize,y*self.tSize))
		if self.type == "map":
			for x, row in enumerate(self.tMap):
				for y, value in enumerate(row):
					self.placeTileDimond(x, y)
					if value == 6:
						self.mountainFix(x, y)
						self.placeMountainTops(x, y)


		randX = self.physics.light

		for x, row in enumerate(self.tMap):
			for y, value in enumerate(row):
				if self.type == "map":
					blitX = x+randX
					if not blitX > self.w-1 and not blitX < 0:
						self.tSurf.fill((255,255,255,255-60*(3-self.light[x,y])),(blitX*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
					elif blitX > self.w-1:
						self.tSurf.fill((255,255,255,255-60*(3)),((blitX-self.w)*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
					elif blitX < 0:
						self.tSurf.fill((255,255,255,255-60*(3)),((blitX+self.w)*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
				elif self.type == "encounter":
					if self.encType == 'cave':
						pass#self.tSurf.fill((255,255,255,200),(x*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
					else:
						lX,lY = self.encXY[0],self.encXY[1]
						if lX<randX:self.tSurf.fill((255,255,255,255-60*3),(x*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
						elif lX-randX > self.w-1: self.tSurf.fill((255,255,255,255-60*3),(x*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)
						else: self.tSurf.fill((255,255,255,255-60*(3-self.mapTiles.light[lX-self.physics.light,lY])),(x*self.tSize,y*self.tSize,self.tSize,self.tSize),special_flags=pygame.BLEND_RGBA_MULT)



	def encFixTileBase(self,x,y):
		tType = self.tMap[x, y]
		try:
			adjTiles = [self.tMap[x,y-1],self.tMap[x+1,y],self.tMap[x,y+1],self.tMap[x-1,y]]
			diagTiles = [self.tMap[x-1,y-1],self.tMap[x+1,y-1],self.tMap[x+1,y+1],self.tMap[x-1,y+1]]
		except:
			return "0"

		if self.type == 'encounter' and self.encType == 'cave' and tType == 2:
			cTiles = [8,8,19,17]
			cInt = 0
			for a in adjTiles:
				if a == tType:
					cInt+=1
			for i,d in enumerate(diagTiles):
				if d < tType and cInt == 4:
					return "2"
		if self.type == 'encounter' and self.encType == 'cave' and tType == 1:
			return "0"
		return "0"

	def getTileBorder(self, x, y, dict,rot=0):
		def swap(a,i,j):
			a[i], a[j] = a[j], a[i]
		def strRotate(b,m,start=0):
			a = list(b)
			n=len(a)-start
			m = m % n
			if m != 0:
				for i in range(start,start+n-m):
					swap(a, i, i+m)
				strRotate (a,m-n%m,start+n-m)
			retStr = ""
			for x in a:
				retStr+=x
			return retStr
		def lstRotate(a,m,start=0):
			n=len(a)-start
			m = m % n
			if m != 0:
				for i in range(start,start+n-m):
					swap(a, i, i+m)
				lstRotate (a,m-n%m,start+n-m)
			return a

		tType = self.tMap[x, y]
		if tType == 1 and self.type == 'encounter' and self.artifact == (x,y):
				return 42
		elif tType == 1 and self.type == 'encounter':
			return  random.choice([30,31,32,37,40,41])
				
		w, h = self.w, self.h
		#if self.type == "encounter":
		#	x,y = y,x
		#	w,h = h,w
		adjTiles = []
		diagTiles = []
		if self.type == 'encounter':
			if not y == 0:
				adjTiles.append(self.tMap[x,y-1])
				if not x == 0:
					diagTiles.append(self.tMap[x-1, y-1])
				else: diagTiles.append(1)
				if not x >= w-1:
					diagTiles.append(self.tMap[x+1, y-1])
				else: diagTiles.append(1)
			else:
				adjTiles.append(1)
				diagTiles.append(1)
				diagTiles.append(1)
			if not x >= w-1:
				adjTiles.append(self.tMap[x+1,y])
				if not y >= h-1:
					diagTiles.append(self.tMap[x+1, y+1])
				else: diagTiles.append(1)
			else:
				adjTiles.append(1)
				diagTiles.append(1)
			if not y >= h-1:
				adjTiles.append(self.tMap[x,y+1])
			else:
				adjTiles.append(1)
			if not x == 0:
				adjTiles.append(self.tMap[x-1,y])
				if not y >= h-1:
					diagTiles.append(self.tMap[x-1,y+1])
				else:
					diagTiles.append(1)
			else:
				adjTiles.append(1)
				diagTiles.append(1)
		else:
			if not y == 0:
				adjTiles.append(self.tMap[x,y-1])
				if not x == 0:
					diagTiles.append(self.tMap[x-1, y-1])
				else: diagTiles.append(0)
				if not x >= w-1:
					diagTiles.append(self.tMap[x+1, y-1])
				else: diagTiles.append(0)
			else:
				adjTiles.append(0)
				diagTiles.append(0)
				diagTiles.append(0)
			if not x >= w-1:
				adjTiles.append(self.tMap[x+1,y])
				if not y >= h-1:
					diagTiles.append(self.tMap[x+1, y+1])
				else: diagTiles.append(0)
			else:
				adjTiles.append(0)
				diagTiles.append(0)
			if not y >= h-1:
				adjTiles.append(self.tMap[x,y+1])
			else:
				adjTiles.append(0)
			if not x == 0:
				adjTiles.append(self.tMap[x-1,y])
				if not y >= h-1:
					diagTiles.append(self.tMap[x-1,y+1])
				else:
					diagTiles.append(0)
			else:
				adjTiles.append(0)
				diagTiles.append(0)
		if tType == 2:
			adjInt = 0
			for a in adjTiles:
				if a < 2: adjInt+=1
			if adjInt == 4:
				return 18
		if tType == 4:
			adjInt = 0
			for a in adjTiles:
				if a < 4: adjInt+=1
			if adjInt == 4:
				return 18
		if rot != 0 and self.type == 'encounter': diagTiles = lstRotate(diagTiles,4-rot)
		if tType == 6:
			mTiles = [57,56,46,47]
			mInt = 0
			for a in adjTiles:
				if a == tType:
					mInt+=1
			for i,d in enumerate(diagTiles):
				if d < tType and mInt == 4:
					return mTiles[i]
		if self.type == 'encounter' and self.encType == 'cave' and tType == 2:
			cTiles = [8,8,19,17]
			cInt = 0
			for a in adjTiles:
				if a == tType:
					cInt+=1
			for i,d in enumerate(diagTiles):
				if d < tType and cInt == 4:
					return cTiles[i] 
		adjTilesStr = str(tType)
		adjTilesStrbRot = ""
		for i,t in enumerate(adjTiles):
			if t < tType:
				adjTilesStrbRot += "0"
			else:
				adjTilesStrbRot += "1"
		if rot == 1 and self.type == 'encounter':
			a = adjTilesStrbRot[3]
			b = adjTilesStrbRot[:3]
			a+=b
			strRot = a
		elif rot != 0 and self.type == 'encounter': 
			strRot = strRotate(adjTilesStrbRot,4-rot)
		else: strRot = adjTilesStrbRot
		adjTilesStr+=strRot
		if adjTilesStr in dict.keys():
			if self.type == 'encounter' and x == w-1:
				if adjTilesStr == "21010":return 17
				elif adjTilesStr == "20011": return 18
				elif adjTilesStr == "21001": return 18
				elif adjTilesStr == "21011": return 18
				else: return 18
			return dict[adjTilesStr]
		elif tType != 0:
			return 11
		else:
			return 35

	def placeTileDimond(self,x,y):
		tType = self.tMap[x,y]
		nDict = {	"00110": 36,"00011": 36,"01001": 36,"01100": 36,
					"20110": 34,"20011": 34,"21001": 34,"21100": 34}
		try:
			adjTiles = [self.tMap[x,y-1],self.tMap[x+1,y],self.tMap[x,y+1],self.tMap[x-1,y]]
			diagTiles = [self.tMap[x-1,y-1],self.tMap[x+1,y-1],self.tMap[x+1,y+1],self.tMap[x-1,y+1]]
		except:
			return

		nAdjTilesStr = str(tType)
		for i,t in enumerate(adjTiles):
			if t <= tType:
				nAdjTilesStr += "0"
			else:
				nAdjTilesStr += "1"
		if nAdjTilesStr in nDict.keys():
			if nAdjTilesStr[1:] == "0110" and diagTiles[2] != tType:
				self.tSurf.blit(self.getTile(nDict[nAdjTilesStr]),(((x+1)*self.tSize)-(self.tSize/2),((y+1)*self.tSize)-(self.tSize/2)))
			elif nAdjTilesStr[1:] == "0011" and diagTiles[3] != tType:
				self.tSurf.blit(self.getTile(nDict[nAdjTilesStr]),(((x)*self.tSize)-(self.tSize/2),((y+1)*self.tSize)-(self.tSize/2)))
			elif nAdjTilesStr[1:] == "1001" and diagTiles[0] != tType:
				self.tSurf.blit(self.getTile(nDict[nAdjTilesStr]),(((x)*self.tSize)-(self.tSize/2),((y)*self.tSize)-(self.tSize/2)))
			elif nAdjTilesStr[1:] == "1100" and diagTiles[1] != tType:
				self.tSurf.blit(self.getTile(nDict[nAdjTilesStr]),(((x+1)*self.tSize)-(self.tSize/2),((y)*self.tSize)-(self.tSize/2)))

	def mountainFix(self,x,y):
		try:
			adjTiles = [self.tMap[x,y-1],self.tMap[x+1,y],self.tMap[x,y+1],self.tMap[x-1,y]]
			diagTiles = [self.tMap[x-1,y-1],self.tMap[x+1,y-1],self.tMap[x+1,y+1],self.tMap[x-1,y+1]]
		except:
			return
		diagInt = 0
		adjInt = 0
		for i in adjTiles:
			if i == 6: adjInt+=1
		for j in diagTiles:
			if j < 6: diagInt+=1

		if adjInt == 4 and diagInt == 2:
			if diagTiles[0] < 6 and diagTiles[2] < 6:
				self.tSurf.blit(self.getTile(11),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(70),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(71),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x+1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(72),(((x+1)*self.tSize),y*self.tSize))	
			else:
				self.tSurf.blit(self.getTile(11),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(80),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(81),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x+1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(82),(((x+1)*self.tSize),y*self.tSize))
		if adjInt == 3 and diagInt == 2:
			if diagTiles[1] < 6 and diagTiles[3] < 6:
				self.tSurf.blit(self.getTile(11),(((x-1)*self.tSize),(y-1)*self.tSize))
				self.tSurf.blit(self.getTile(50),(((x-1)*self.tSize),(y-1)*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(80),(((x-1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(81),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x+1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(82),(((x+1)*self.tSize),y*self.tSize))
			elif diagTiles[0] < 6 and diagTiles[2] < 6:
				self.tSurf.blit(self.getTile(11),(((x+1)*self.tSize),(y-1)*self.tSize))
				self.tSurf.blit(self.getTile(50),(((x+1)*self.tSize),(y-1)*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(71),(((x)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(11),(((x+1)*self.tSize),y*self.tSize))
				self.tSurf.blit(self.getTile(72),(((x+1)*self.tSize),y*self.tSize))	
	def placeMountainTops(self,x,y):
		def isPlaceSuitable(x,y):
			try:
				adjTiles = [self.tMap[x,y-1],self.tMap[x+1,y],self.tMap[x,y+1],self.tMap[x-1,y],self.tMap[x-1,y-1],self.tMap[x+1,y-1],self.tMap[x+1,y+1],self.tMap[x-1,y+1]]
			except:
				return
			centerTiles = 0
			if adjTiles[4] < 6: centerTiles-=1
			for i,tile in enumerate(adjTiles):
				if  i == 1 or i == 6 or i == 2:
					if i==1:
						g,h = (x+1),(y)
					elif i==6:
						g,h = (x+1),(y+1)
					else:
						g,h = (x),(y+1)
					try:
						adjAdjTiles = [self.tMap[g,h-1],self.tMap[g+1,h],self.tMap[g,h+1],self.tMap[g-1,h],self.tMap[g-1,h-1],self.tMap[g+1,h-1],self.tMap[g+1,h+1],self.tMap[g-1,h+1]]
						bTiles = 0
						for k in adjAdjTiles:
							if k < 6:bTiles+=1
						if bTiles==0:
							centerTiles+=1
					except:
						continue
			if centerTiles == 3:
				return True
			else:
				return False
		def isOccupied(x,y):
			retBool = False
			for coord in self.mountainTops:
				if x-1 == coord[0]:
					if y == coord[1] or y-1 == coord[1] or y+1 == coord[1]:
						retBool=True
				if y-1 == coord[1]:
					if x == coord[0] or x+1 == coord[0]:
						retBool=True
			return retBool
		suitable = isPlaceSuitable(x,y)
		if suitable:
			if not isOccupied(x,y):
				print "Flip..."
				if rn.rand() <= 0.4:
					print "Mountain Top Got!",x,y
					self.mountainTops.append([x,y])
					mTopType = rn.rand() <= 0.7
					if mTopType: mTopType = 44
					else: mTopType = 66
					self.tSurf.blit(self.getTile(mTopType),(((x)*self.tSize),(y)*self.tSize))
					self.tSurf.blit(self.getTile(mTopType+1),(((x+1)*self.tSize),(y)*self.tSize))
					self.tSurf.blit(self.getTile(mTopType+10),(((x)*self.tSize),(y+1)*self.tSize))
					self.tSurf.blit(self.getTile(mTopType+11),(((x+1)*self.tSize),(y+1)*self.tSize))
		else:
			try:
				adjTiles = [self.tMap[x,y-1],self.tMap[x+1,y],self.tMap[x,y+1],self.tMap[x-1,y],self.tMap[x-1,y-1],self.tMap[x+1,y-1],self.tMap[x+1,y+1],self.tMap[x-1,y+1]]
			except:
				return
			b = 0
			for a in adjTiles:
				if a < 6:
					b+=1
			if not isOccupied(x,y) and b==0:
				if rn.rand() <= 0.2 :
					if random.randint(0,1):
						self.tSurf.blit(self.getTile(64),(x*self.tSize,y*self.tSize))
					else:
						self.tSurf.blit(self.getTile(65),(x*self.tSize,y*self.tSize))
	def getTile(self,nr):
		hNr = nr % 10
		vNr = nr / 10
		t = pygame.Surface((self.tSize,self.tSize),pygame.SRCALPHA,32).convert_alpha()
		t.blit(self.tSet,(0,0),(hNr*self.tSize,vNr*self.tSize,self.tSize,self.tSize))
		return t

	def getPlayerSprite(self,nr):
		# These should be blitted to a surface on load
		# instead of blitting every frame.
		t = None
		if self.type == "map":
			t = pygame.Surface((self.tSize,self.tSize),pygame.SRCALPHA,32).convert_alpha()
			t.blit(self.tSetPlayer,(0,0),(nr*self.tSize,0,self.tSize,self.tSize))
		else:
			if nr == 0 or nr == 1: nr = 2
			elif nr == 7: nr = 3
			elif nr <= 4: nr = 0
			else: nr = 1
			t = pygame.Surface((32, 64), pygame.SRCALPHA, 32).convert_alpha()
			t.blit(self.tSetPlayer, (0,0), (32 * nr, 0, 32, 64))
		return t

	def getMap(self,w,h):
		aSurf = pygame.Surface((w,h))
		aSurf.blit(self.tSurf,(0,0),area=(self.x,self.y,w,h))
		return aSurf

	def setXY(self,x=0,y=0):
		self.x = x
		self.y = y
		if self.x < 0: self.x = 0
		if self.y < 0: self.y = 0
		w, h = self.tSurf.get_size()
		if self.x > w - self.screenSize[0]: self.x = w - self.screenSize[0]
		if self.y > h - self.screenSize[1]: self.y = h - self.screenSize[1]
		return self.x, self.y

	def getTileType(self, x, y):
		try:
			return self.tMap[self.x / float(self.tSize) + x / float(self.tSize)][self.y / float(self.tSize) + y / float(self.tSize)]
		except:
			return 0

	def addEncounter(self,XY):
		imgEnc = pygame.image.load("encounter_icon.png")
		x,y = XY[0],XY[1]
		if x< self.physics.light:	imgEnc.fill((255-40*(3-0),255-40*(3-0),255-40*(3-0)),special_flags=pygame.BLEND_RGBA_MULT)
		elif x-self.physics.light > self.w-1:	imgEnc.fill((255-40*(3-0),255-40*(3-0),255-40*(3-0)),special_flags=pygame.BLEND_RGBA_MULT)
		else: imgEnc.fill((255-40*(3-self.light[x-self.physics.light,y]),255-40*(3-self.light[x-self.physics.light,y]),255-40*(3-self.light[x-self.physics.light,y])),special_flags=pygame.BLEND_RGBA_MULT)
		self.tSurf.blit(imgEnc,((XY[0])*self.tSize,(XY[1])*self.tSize))	

if __name__ =='__main__':
	pygame.init()
	w = 800
	h = 600
	mapW = tweaks['mapW']
	mapH = tweaks['mapH']
	tMap = mapgen.segment_map(mapgen.nm(mapW,mapH,tweaks['prob'],tweaks['its']))
	screen = pygame.display.set_mode((w,h))
	tSet = pygame.image.load("testTiles.jpg")
	t = Tiles(mapW,mapH,tMap,tSet)
	t.createSurface()
	spd=3
	#screen.blit(t.createSurface(),(200,100))
	while True:
		screen.blit(t.getMap(w,h),(0,0))
		pygame.display.update()
		pygame.event.pump()
		keys = pygame.key.get_pressed()
		#print keys[pygame.K_w]
		if keys[pygame.K_w]: 	t.setXY(y=-1*spd)
		elif keys[pygame.K_s]:	t.setXY(y=1*spd)
		if keys[pygame.K_a]:	t.setXY(x=-1*spd)
		elif keys[pygame.K_d]: 	t.setXY(x=1*spd)



