import random

NEARBY = (None,None,None,None,None,None,None,None)
GLOBAL_TEMP_FACTOR = 0.2
MAXX = 190
MAXY = 190
MINY = 10
toremove = []
changed = []
changedempty = []
class Element(object):
	moverate = 0.5
	specific_heat = 1
	conductivity = 1
	basecolor = (255,255,255)
	name = "Base Element"
	gravity = 0
	density = 100
	liquid = False
	removed = False
	def __init__(self,x,y,grid,active,temperature=295.0):
		self.x, self.y = x,y
		self.temperature=temperature
		self.grid = grid
		self.active = active
		self.on_create()
	def on_create(self):
		pass
	def register(self):
		global changed
		self.active.append(self)
		self.grid[self.x][self.y] = self
		changed += [(self.x,self.y)]
	def remove(self):
		global changedempty
		changedempty += [(self.x,self.y)]
		self.grid[self.x][self.y] = None
		toremove.append(self)
		self.removed = True
		if self in self.active:
			self.active.remove(self)
	def transform(self,final):
		new = final(self.x,self.y,self.grid,self.active,self.temperature)
		new.register()
		self.remove()
	def position(self):
		return (self.x,self.y)
	def move(self,direction=(0,1),gravity=True):
		'''sets a new x&y position based on a direction tuple'''
		global changed
		global changedempty
		if self.removed:
			return
		oldx = self.x
		oldy = self.y
		self.x = self.x + direction[0]
		self.y = self.y + direction[1]
		if self.x <= 1:
			self.x = 2
		elif self.x  >= (MAXX +1):
			self.x = MAXX


		self.grid[oldx][oldy] = None
		self.grid[self.x][self.y] = self
		if self.y <= MINY:
			self.remove()
			return
		elif self.y >= (MAXY):
			self.remove()
			return
		changed.append((self.x,self.y))
		changedempty.append((oldx,oldy))
	def act(self):
		'''does stuff based on what is around this item.
		nearby is a tuple containing a clockwise list of
		elements next to this one starting at the top left
		0	1	2
		7	x	3
		6	5	4
		
		'''
		nearby = self.nearby()
		nb = [n for n in nearby if n is not None and n is not BOUNDARY]
		for n in nb:
			self.temperate(n)
		nb = [n for n in nearby if n is not BOUNDARY]
		for n in nb:
			self.reaction(n)
		if all(nearby):
			return
		if self.gravity > 0:
			if random.random() < self.moverate:
				if nearby[5] is None:
					self.move((0,1))
				elif nearby[5] is not BOUNDARY and self.name != nearby[5].name:
					self.densitycheck(nearby[5])
				elif nearby[6] is None:
					self.move((-1,1))
				elif nearby[4] is None:
					self.move((1,1))
				elif nearby[7] is None and self.liquid:
					self.move((-1,0))
				elif nearby[3] is None and self.liquid:
					self.move((1,0))
		elif self.gravity < 0:
			if random.random() < self.moverate:
				if nearby[1] is None:
					self.move((0,-1))
				elif nearby[0] is None:
					self.move((-1,-1))
				elif nearby[2] is None:
					self.move((1,-1))
				elif nearby[7] is None and self.liquid:
					self.move((-1,0))
				elif nearby[3] is None and self.liquid:
					self.move((1,0))
				else:
					pass
	def last_thing():
		pass

	def temperate(self,touching):
		kc = min(self.conductivity,touching.conductivity)
		dt = (self.temperature-touching.temperature)*kc*GLOBAL_TEMP_FACTOR
		self.temperature -= dt
		touching.temperature += dt
		self.temp_action()

	def densitycheck(self,item):
		'''checks density of what's below to see if it can take its place'''
		if item.density < self.density:
			x0 = self.x
			y0 = self.y
			x1 = item.x
			y1 = item.y
			self.x = x1
			self.y = y1
			item.x = x0
			item.y = y0
			self.grid[self.x][self.y] = self
			self.grid[item.x][item.y] = item

	def temp_action(self):
		pass

	def color(self):
		return self.basecolor

	def nearby(self):
		x = self.x
		y = self.y
		grid = self.grid
		n0 = grid[x-1][y-1]
		n1 = grid[x][y-1]
		n2 = grid[x+1][y-1]
		n3 = grid[x+1][y]
		n4 = grid[x+1][y+1]
		n5 = grid[x][y+1]
		n6 = grid[x-1][y+1]
		n7 = grid[x-1][y]
		return (n0,n1,n2,n3,n4,n5,n6,n7)
	def reaction(self,touching):
		pass

class Boundary(Element):
	name = 'boundary'
	basecolor = (255,255,255)
	moverate = 0
	gravity = 0
	density = 1000
	liquid = False
	def __init__(self,x=0,y=0,grid=None,active=None,temperature=295.0):
		self.x, self.y = x,y
		self.temperature=temperature
		self.grid = grid
		self.active = active

BOUNDARY = Boundary()

class Water(Element):
	name = "Water"
	basecolor = (50,50,255)
	specific_heat = 100
	moverate = .7
	gravity = 1
	density = 20
	liquid = True
	def temp_action(self):
		if self.temperature > 378:
			if random.random() < .5:
				self.transform(Steam)

class Oil(Element):
	name = 'Oil'
	basecolor = (180,180,180)
	moverate = .2
	gravity = 1
	density = 10
	specific_heat = 50
	liquid = True
	def temp_action(self):
		if self.temperature > 500:
			if random.random() < .2:
				self.transform(Fire)

class Steam(Element):
	name = "Steam"
	basecolor = (50,50,150)
	moverate = .8
	gravity = -1
	density = 1
	specific_heat = 120
	liquid = True
	def temp_action(self):
		if self.temperature < 370:
			if random.random() < .5:
				self.transform(Water)

class Wall(Element):
	name = "Wall"
	basecolor = (100,100,100)
	moverate = .5
	gravity = 0
	liquid = False
	density = 100
	specific_heat = 30
	def color(self):
		return (max(100,min(self.temperature/2,255)),100,100)

class Fire(Element):
	name = 'Fire'
	basecolor = (200,50,50)
	moverate = .5
	gravity = -1
	density = 1
	liquid = True
	specific_heat = 100
	def on_create(self):
		self.temperature = 1000
	def temp_action(self):
		if random.random() > .99:
			self.remove()
