from ableton.v2.base import listens
from ableton.v2.control_surface import Component
from ableton.v2.control_surface.components import SessionRingComponent, RightAlignTracksTrackAssigner, ScrollComponent, TransportComponent
from ableton.v2.control_surface.control import ButtonControl

from .mixer import ExquisMixerComponent
from .channel_strip import ColoredChannelStripComponent
from .. import colors
from ..color import Color, SelectedTrackColor
from ..util import all_tracks

class TracksModeComponent(Component):
	"A component that handles the Tracks mode of the Exquis, displaying the tracks of the current Live set"
	
	down_button = ButtonControl()
	encoder0_push = ButtonControl()
	encoder1_push = ButtonControl()
	encoder2_push = ButtonControl()
	encoder3_push = ButtonControl()

	def __init__(self, *a, **k):
		self.encoders = []
		super(TracksModeComponent, self).__init__(*a, **k)

		self.session_ring = SessionRingComponent(
			name="TracksSessionRing",
			num_tracks=55,
			num_scenes=1,
			tracks_to_use=lambda: tuple(self.song.visible_tracks) + tuple(self.song.return_tracks) + (self.song.master_track,),
		)

		self.mixer = ExquisMixerComponent(
			name="TracksMixer",
			tracks_provider=self.session_ring,
			track_assigner=RightAlignTracksTrackAssigner(song=self.song, include_master_track=True),
		)

		self.transport = TransportComponent(
			name="TracksTransport",
		)

		self.selected_strip = ColoredChannelStripComponent()
		self.add_children(self.selected_strip)

		self.on_selected_track_changed.subject = self.song.view
		self.on_selected_track_changed()

		self.scroll = ScrollComponent(
			name="TracksScroll",
			scrollable=self,
		)
		self.scroll.scroll_up_button.color = SelectedTrackColor(self.song.view, track_provider=self.session_ring, offset=-1)
		self.scroll.scroll_up_button.pressed_color = Color(3)
		self.scroll.scroll_down_button.color = SelectedTrackColor(self.song.view, track_provider=self.session_ring, offset=1)
		self.scroll.scroll_down_button.pressed_color = Color(3)
	
	def can_scroll_up(self):
		selected_track = self.song.view.selected_track
		tracks = all_tracks(self.song)
		return tracks.index(selected_track) > 0

	def can_scroll_down(self):
		selected_track = self.song.view.selected_track
		tracks = all_tracks(self.song)
		return tracks.index(selected_track) < len(tracks) - 1
	
	def scroll_up(self):
		selected_track = self.song.view.selected_track
		tracks = all_tracks(self.song)
		index = tracks.index(selected_track)
		if index > 0:
			previous_track = tracks[index - 1]
			follow_arm = False
			if previous_track.can_be_armed and selected_track.can_be_armed and selected_track.arm:
				follow_arm = True
				selected_track.arm = False
			
			self.song.view.selected_track = previous_track
			
			selected_track = self.song.view.selected_track
			if follow_arm and selected_track.can_be_armed and not selected_track.arm:
				selected_track.arm = True
	
	def scroll_down(self):
		selected_track = self.song.view.selected_track
		tracks = all_tracks(self.song)
		index = tracks.index(selected_track)
		if index < len(tracks) - 1:
			next_track = tracks[index + 1]
			follow_arm = False
			if selected_track.can_be_armed and next_track.can_be_armed and selected_track.arm:
				follow_arm = True
				selected_track.arm = False

			self.song.view.selected_track = next_track
			selected_track = self.song.view.selected_track

			if follow_arm and selected_track.can_be_armed and not selected_track.arm:
				selected_track.arm = True
	
	def set_track_select_buttons(self, _):
		self.mixer.set_track_select_buttons(_)

	def update(self):
		if self.is_enabled():
			self._update_encoder_colors()
		super(TracksModeComponent, self).update()

	def _update_encoder_colors(self):
		if len(self.encoders) < 4:
			return
		
		self.encoders[0].palette_index = 21 # Volume
		self.encoders[1].is_bidirectional = True # Pan
		self.encoders[1].palette_index = 128
		self.encoders[2].palette_index = colors.color_value(self.song.return_tracks[0].color) if len(self.song.return_tracks) > 0 else 0
		self.encoders[3].palette_index = colors.color_value(self.song.return_tracks[1].color) if len(self.song.return_tracks) > 1 else 0

	@listens("selected_track")
	def on_selected_track_changed(self):
		self.selected_strip.set_track(self.song.view.selected_track)
	
	def set_encoders(self, _):
		if _ and len(_) >= 4:
			self.encoders = _
			self.selected_strip.set_volume_control(_[0])
			self.selected_strip.set_pan_control(_[1])
			self.selected_strip.set_send_controls((_[2], _[3]))
			self._update_encoder_colors()
		else:
			self.encoders = []
			self.selected_strip.set_volume_control(None)
			self.selected_strip.set_pan_control(None)
			self.selected_strip.set_send_controls(None)

	def set_left_button(self, _):
		self.scroll.set_scroll_up_button(_)
	
	def set_right_button(self, _):
		self.scroll.set_scroll_down_button(_)

	def set_up_button(self, _):
		self.transport.set_metronome_button(_)

	@down_button.pressed
	def on_down_button_pressed(self, _):
		self.song.tap_tempo()

	@encoder0_push.pressed
	def on_encoder0_push_pressed(self, _):
		if self.selected_strip._volume_control is None:
			return
		param = self.selected_strip._volume_control.mapped_parameter()
		if param is not None and param.is_enabled:
			param.value = param.default_value
	
	@encoder1_push.pressed
	def on_encoder1_push_pressed(self, _):
		if self.selected_strip._pan_control is None:
			return
		param = self.selected_strip._pan_control.mapped_parameter()
		if param is not None and param.is_enabled:
			param.value = param.default_value

	@encoder2_push.pressed
	def on_encoder2_push_pressed(self, _):
		if self.selected_strip._send_controls is None or len(self.selected_strip._send_controls) < 1:
			return
		param = self.selected_strip._send_controls[0].mapped_parameter()
		if param is not None and param.is_enabled:
			param.value = param.default_value

	@encoder3_push.pressed
	def on_encoder3_push_pressed(self, _):
		if self.selected_strip._send_controls is None or len(self.selected_strip._send_controls) < 2:
			return
		param = self.selected_strip._send_controls[1].mapped_parameter()
		if param is not None and param.is_enabled:
			param.value = param.default_value
