class DaisyDriver(Serial):
	
	def __init__(self, connected = True):
		# check for connection bool to allow for dummy DaisyDriver object
		# if not connected
		if connected:
			# initialise DaisyDriver serial object (hard code serial address for now)
			super(DaisyDriver, self).__init__('/dev/ttyACM0')
			
			# set initial speed (0,1,2 for low,medium,high respectively)
			self.speedset(2)
			
			# initialise jog lock
			self.DDlock = Lock()
			
			# initialise direction dictionary, f = forward, fl = forward left etc...
			self.directions = {'l':(0, -1, 0),
								'r':(0, 1, 0),
								'f':(-1, 0, 0),
								'fl':(-1, -1, 0),
								'fr':(-1, 1, 0),
								'b':(1, 0, 0),
								'bl':(1, -1, 0),
								'br':(1, 1, 0),
								'u':(0, 0, -1),
								'd':(0, 0, 1)}
								
		elif not connected:
			# just set default speedval for slider to read
			self.speedval = 2
			
		# state value of light, assumes on then switches off
		self.lightval = 1
		self.light_off()
		
		self.lightAVG = [0]*5
		self.lightAVGindx = 0
		
		self.MOVAVGLEN = 50
		self.MOVAVG = [0]*self.MOVAVGLEN
		self.MOVAVGindx = 0
		
		
	def speedset(self, val):
		# speed val
		self.speedval = val
		
		# value from slider equals 0, 1 or 2. Use list for converting 
		# slider index to step motor speed
		speeds = [50, 275, 500]
		
		# serial command
		command = 'STV 0 {V} {V} {V} \r'.format(V=speeds[self.speedval])
		
		# convert to byte string
		bytes_command = command.encode('utf-8')
		
		# write command
		self.write(bytes_command)
		
		# flush buffer
		self.flush()
		
	def __jogdo(self, x, y, z):
		# enable lock
		with self.DDlock:
						
			# flush buffer
			self.flush()
			
			# serial command
			command = 'JOG 0 {x_} {y_} {z_} \r'.format(x_=x, y_=y, z_=z)
			
			# convert to byte string
			bytes_command = command.encode('utf-8')
			
			# write command
			self.write(bytes_command)
			
			# read finish statement
			self.readline()
			
	def __jog(self, x, y, z, button_handle):
		# count, button status dependent
		count = 0
		
		# upper limit on jog repeats
		while count < 1000:
			if (count == 0):
				self.__jogdo(x, y, z)
		
			elif button_handle.isDown():
				self.__jogdo(x, y, z)
				
			count+=1
		
	def jog(self, direction, button_handle):
		# if not locked then jog
		if not self.DDlock.locked():
			# get direction vector
			dir_tuple = self.directions[direction]
			# start jog
			jogthread = Thread(target=self.__jog, args=(*dir_tuple, button_handle))
			jogthread.start()
			
	def light_on(self):
		# switch light on, if not on already
		if self.lightval==0:
			# serial command
			bytes_command = b'LON \r'
			
			# write command
			self.write(bytes_command)
			
			# set light state as on
			self.lightval = 1
			
			# flush buffer
			self.flush()
			
	def light_off(self):
		# switch light off, if not off already
		if self.lightval==1:
			# serial command
			bytes_command = b'LOF \r'
			
			# write command
			self.write(bytes_command)
			
			# set light state as off
			self.lightval = 0
			
			# flush buffer
			self.flush()
			
	def get_light_sensor_val(self, figure_update_function):
		if self.DDlock.acquire(timeout=1.0):
			self.flush()
			command = 'NET 1 LTM \r'
			print(command)
			bytes_command = command.encode('utf-8')
			self.write(bytes_command)
			
			val = int(self.readline().decode("utf-8"))
			
			if val>=50:
				val=49
			
			self.lightAVG[self.lightAVGindx] = val
			self.lightAVGindx = (self.lightAVGindx + 1)%5
			
			self.MOVAVG[self.MOVAVGindx] = val
			self.MOVAVGindx = (self.MOVAVGindx + 1)%self.MOVAVGLEN
			
			lightavg = sum(self.lightAVG)/5
			
			movavg = sum(self.MOVAVG)/self.MOVAVGLEN
			
			figure_update_function(lightavg)
			
			if self.MOVAVGindx%25==0:
				sleep(100e-3)
				command = 'NET 2 MOV {x_} {x_} {x_} \r'.format(x_=int(movavg*80))
				print(command)
				bytes_command = command.encode('utf-8')
				self.write(bytes_command)
				#~ sleep(SOME TIME CALCULATED ACCORDING TO MOVE DISTANCE!)
			
			self.DDlock.relase()