from Updateable import Updateable
from Drawable 	import Drawable
from Moveable 	import Moveable
from Box 		import Box
from Config		import Config

delivery_debug = Config.get_val("delivery_debug")
score = Config.get_val("score")

class Delivery_Block(Drawable, Updateable):
	delivery_blocks = {}

	def __init__(self, pos=[0,0], col=[30,30,30], delivering=1, time=1):
		super(Delivery_Block, self).__init__(pos, col)
		Updateable.__init__(self)

		self.delivering = delivering
		self.time = time
		self.counter = 0

		if tuple(self.position) in Delivery_Block.delivery_blocks:
			del Delivery_Block.delivery_blocks[tuple(self.position)]
			print("Delivery Block Overlap Detected") if delivery_debug else 0

		Delivery_Block.delivery_blocks[tuple(self.position)] = self
		print("Delivery Block created\n  Delivering: " + str(delivering) + "\n  Time: " + str(time)) if delivery_debug else 0

	def update_self(self, dt):

		score = 0
		self.counter += dt
from Updateable import Updateable
from Drawable 	import Drawable
from Moveable 	import Moveable
from Config		import Config
from Robot 		import Robot

programmer_debug = Config.get_val("programmer_debug")

class Programmer(Drawable, Updateable):
	programmers = {}

	def __init__(self, pos=[0,0], col=(210,210,210), program=""):
		super(Programmer, self).__init__(pos, col)
		Updateable.__init__(self)

		self.program = program

		if tuple(self.position) in Programmer.programmers: # A new programmer placecd on an old one will replace it
			del Programmer.programmers[tuple(self.position)]

		Programmer.programmers[tuple(self.position)] = self
		print("Programmer succesfully added") if programmer_debug else 0

	def update_self(self, dt):
		print("Programmer updating self") if programmer_debug else 0

		if tuple(self.position) in Moveable.moveables:
			m = Moveable.moveables[tuple(self.position)]
			print("  Something in the same position") if programmer_debug else 0
			if type(m) is Robot:
				m.set_instruction(self.program)
from pyglet.gl import *
from Config		import Config

size = Config.get_val("size")
draw_debug = Config.get_val("draw_debug")

class Drawable:
	drawables = []
	top_layer = 0

	def __init__(self, pos=[0,0], col=(255,255,255), layer=0):
		self.position = pos
		self.shape = [self.position[0], self.position[1], self.position[0] + size, self.position[1], self.position[0] + size, self.position[1] + size, self.position[0], self.position[1] + size]
		self.colour = col
		self.layer = layer
		if layer > Drawable.top_layer:
			Drawable.top_layer = layer
		Drawable.drawables.append(self)

	@staticmethod
	def draw():
		for l in range(Drawable.top_layer+1): # Draws all drawables, lowest layers first
			for d in Drawable.drawables:
				d.draw_self() if d.layer == l else 0

	def draw_self(self):
		print("Colour :" + str((self.colour + self.colour + self.colour + self.colour))) if draw_debug else 0
		
		pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2i', self.shape), ('c3B', (self.colour + self.colour + self.colour + self.colour)))

	def delete(self):
from Config import Config

parser_debug = Config.get_val("parser_debug")
size = Config.get_val("size")

class Programmable:
	def __init__(self, instruction=""):
		self.instruction = instruction # Not using set_instruction due to it being overridden by subclasses
		self.current_instruction = [instruction.split("(")[1].split(",")[0], -1]

	def set_instruction(self, inst):
		self.instruction = inst
		self.current_instruction = [inst.split("(")[1].split(",")[0], -1] # Sets current instruction to first instruction name

	def sensor(self, side=""):
		print("    Sensor called on side: " + side) if parser_debug else 0

		if side == "w":
			vector = [self.position[0], self.position[1] + size]
		elif side == "a":
			vector = [self.position[0] - size, self.position[1]]
		elif side == "s":
			vector = [self.position[0], self.position[1] - size]
		elif side == "d":
			vector = [self.position[0] + size, self.position[1]]

		return (self.collides(vector)[0] == 1)

	def run_instruction(self):
		if len(self.instruction) < 1: # Checks that there are instructions to use 
			return
from Config		import Config

update_debug = Config.get_val("update_debug")
update_count = Config.get_val("update_count")

class Updateable:
	updateables = []

	update_counter = 0
	update_time = 0.5

	def __init__(self):
		Updateable.updateables.append(self)

	def update_self(self):
		return 0

	@staticmethod
	def update(dt, time):
		global update_count
		Updateable.update_counter += dt

		if Updateable.update_counter > Updateable.update_time:
			score = 0

			Updateable.update_counter = 0
			update_count += 1
			
			print("\n\nStarting Moveables update " + str(update_count) + " on " + str(len(Updateable.updateables)) + " updateables at time " + str(time) + " seconds") if update_debug else 0

			for u in Updateable.updateables:
from Programmable import Programmable
from Drawable import Drawable
from Config import Config

size = Config.get_val("size")
visualiser_debug = Config.get_val("visualiser_debug")

class Program_Visualiser(Programmable, Drawable):

	bit_masks = (7, 11, 13, 14)
	max_recursion = 10
	total_visualisers = 0

	def __init__(self, pos, instruction="(1,,w->2/a->3/s->4/d->5)(2,w,)(3,a,)(4,s,)(5,d,)", current_instruction=0, recursion=0):

		super(Program_Visualiser, self).__init__(instruction)
		Drawable.__init__(self, pos, (120, 10, 120), 1)

		Program_Visualiser.total_visualisers += 1

		self.recursion = recursion + 1
		self.children = []
		self.sensor_val = [0000]
		self.sensor_combination(0)

		if current_instruction:
			self.current_instruction = current_instruction.copy()
		else:
			super(Program_Visualiser, self).set_instruction(instruction)

		print("\nNew Program Visualiser\nPosition: " + str(pos) + "\nInstruction: " + instruction +  "\nCurrent Instruction: " + str(self.current_instruction) + "\nRecursion Level: " + str(recursion) + "\nTotal Visualisers: " + str(Program_Visualiser.total_visualisers)) if visualiser_debug else 0
from Moveable 	import Moveable
from Programmable import Programmable
from Config		import Config

size = Config.get_val("size")

class Robot(Moveable, Programmable):
	def __init__(self, pos=[0,0], col=(0,255,0), instruction="(1,,w->2/a->3/s->4/d->5)(2,w,)(3,a,)(4,s,)(5,d,)"):
		super(Robot, self).__init__(pos, col)
		Programmable.__init__(self, instruction)

	def update_self(self, dt):
		super(Robot, self).update_self(0)
		self.run_instruction()
		return 0
from Updateable import Updateable
from Drawable 	import Drawable
from Moveable 	import Moveable
from Config		import Config

conveyor_debug = Config.get_val("conveyor_debug")

class Conveyor(Drawable, Updateable):
	conveyors = {}

	def __init__(self, pos=[0,0], col=(255,255,0), dir="w"):
		super(Conveyor, self).__init__(pos, col)
		Updateable.__init__(self)
		self.dir = dir

		if tuple(self.position) in Conveyor.conveyors: # Avoids double ups
			del Conveyor.conveyors[tuple(self.position)]

		Conveyor.conveyors[tuple(self.position)] = self

	def update_self(self, dt):
		print("Conveyor Direction: " + self.dir) if conveyor_debug else 0
		if tuple(self.position) in Moveable.moveables:
			m = Moveable.moveables[tuple(self.position)]

			if self.dir == "w":
				m.move_up()
			elif self.dir == "a":
				m.move_left()
			elif self.dir == "s":
				m.move_down()
from Updateable import Updateable
from Drawable 	import Drawable
from Config		import Config

size = Config.get_val("size")
window_width = Config.get_val("window_width")
window_height = Config.get_val("window_height")
collision_debug = Config.get_val("collision_debug")
move_debug = Config.get_val("move_debug")

class Moveable(Drawable, Updateable):
	moveables = {}

	def __init__(self, pos=[0,0], col=(0,0,0)):
		super(Moveable, self).__init__(pos, col, layer=1)
		Updateable.__init__(self)
		self.move_limit = 1 # Total distance moveable can travel in a single update.
		self.move_count = 0 # Total distance moveable has moved in this update

		if(self.collides()[0]):
			raise Exception("Don't stack the boxes, this is a 2D game! Collision at: " + str(self.position))
			Drawable.delete(self)
		else:
			Moveable.moveables[tuple(pos)] = self

	def delete(self):
		Drawable.delete(self)
		del Moveable.moveables[tuple(self.position)]

	def update_pos(self):
		diff = [int(self.position[0] - self.shape[0]), int(self.position[1] - self.shape[1])]