class SelectedTrackControl:
	__module__ = __name__
	__doc__ = 'MIDI Remote Script to control the selected track'
	__name__ = "SelectedTrackControl MIDI Remote Script"
	
	def __init__(self, c_instance):
		#log("SelectedTrackControl::__init__")
		self.c_instance = c_instance
		
		# mappings for registered MIDI notes/CCs
		self.midi_callbacks = {}
		
		# lookup object for fast lookup of cc to mode
		self.midi_cc_to_mode = {}
		# parse midi_mapping recursive for MIDI.CC
		self.mapping_parse_recursive(settings.midi_mapping.values())
		
		self._device_control = DeviceControl(c_instance, self)
		
		self.components = (
			SessionControl(c_instance, self),
			MixerControl(c_instance, self),
			GlobalControl(c_instance, self),
			ViewControl(c_instance, self),
			self._device_control,
			QuantizationControl(c_instance, self),
		)
		
	def mapping_parse_recursive(self, mapping):
		tuple_type = type((1,2));
		for command in mapping:
			if type(command) == tuple_type:
				self.mapping_parse_recursive(command)
			elif isinstance(command, MIDI.CC):
				#log("MIDI CC %d is %s" % (command.key, command.mode))
				self.midi_cc_to_mode[command.key] = command.mode
		
	
	def suggest_map_mode(self, cc_no):
		#log("suggest_map_mode")
		if cc_no in self.midi_cc_to_mode:
			return self.midi_cc_to_mode[cc_no]
		return MIDI.ABSOLUTE # see MIDI.py for definitions of modes
	
	
	def disconnect(self):
		for c in self.components:
			c.disconnect()
	
	def refresh_state(self):
		#log("refresh_state")
		#for c in self.components:
		#	c.refresh_state()
		pass
	
	def update_display(self):
		#log("update_display")
		#for c in self.components:
		#	c.update_display()
		pass
	
	def connect_script_instances(self, instanciated_scripts):
		pass
	
	# called from Live to build the MIDI bindings
	def build_midi_map(self, midi_map_handle):
		#log("SelectedTrackControl::build_midi_map")
		script_handle = self.c_instance.handle()
		
		for channel in range(16):
			callbacks = self.midi_callbacks.get(channel, {})
			
			for note in callbacks.get(MIDI.NOTEON_STATUS,{}).keys():
				Live.MidiMap.forward_midi_note(script_handle, midi_map_handle, channel, note)
			
			for cc in callbacks.get(MIDI.CC_STATUS,{}).keys():
				Live.MidiMap.forward_midi_cc(script_handle, midi_map_handle, channel, cc)
	
	
	
	
	# called from Live when MIDI messages are received
	def receive_midi(self, midi_bytes):
		channel = (midi_bytes[0] & MIDI.CHAN_MASK)
		status = (midi_bytes[0] & MIDI.STATUS_MASK)
		key = midi_bytes[1]
		value = midi_bytes[2]
		
		#log("receive_midi on channel %d, status %d, key %d, value %d" % (channel, status, key, value))
		
		# execute callbacks that are registered for this event
		callbacks = self.midi_callbacks.get(channel,{}).get(status,{}).get(key,[])
		mode = MIDI.ABSOLUTE
		if status == MIDI.CC_STATUS:
			# get mode and calculate signed int for MIDI value
			mode = self.suggest_map_mode(key)
			value = MIDI.relative_to_signed_int[mode](value)
		
		for callback in callbacks:
			callback(value, mode, status)


	def suggest_input_port(self):
		return str('Kimidi Input')

	def suggest_output_port(self):
		return str('Kimidi Output')

	def can_lock_to_devices(self):
		return True

	def lock_to_device(self, device):
		assert (self._device_control != None)
		self._device_control.set_lock_to_device(True, device)

	def unlock_from_device(self, device):
		assert (self._device_control != None)
		self._device_control.set_lock_to_device(False, device)
	
	def set_appointed_device(self, device):
		assert ((device == None) or isinstance(device, Live.Device.Device))
		assert (self._device_control != None)
		self._device_control.set_device(device)
	
	
	# internal method to register callbacks from different controls
	def register_midi_callback(self, callback, key, mode, status, channel):
		if not channel in self.midi_callbacks:
			self.midi_callbacks[channel] = {}
		
		if not status in self.midi_callbacks[channel]:
			self.midi_callbacks[channel][status] = {
				key: [callback,]
			}
		else:
			if key in self.midi_callbacks[channel][status]:
				self.midi_callbacks[channel][status][key].append(callback)
			else:
				self.midi_callbacks[channel][status][key] = [callback, ]