#
# Queue Selector - Quod Libet plugin to randomly adds songs to the queue
# (c) Haran Shivanan <shivanan@statictype.org>
# http://statictype.org/software/qlq
# 
# History:
# 0.0.1: Initial release (ie, "Works for me")
# 
import sys
import random
import gtk
import math
import library
import qltk
import player
import widgets
import config
from formats._audio import AudioFile
RATING = "~#rating"
class Selector:
	"""This class is used to randomly select items from a sorted list.
	It takes a 'skew' parameter that skews the random selection
	towards one end of the list."""
	def __init__(self,count,skew):
		self.size = count
		self.skew = skew
	def Select(self,sorted_list):
		def f(c,x):
			e = math.exp
			return 1 - (e(-c*x)-e(-c))/(1-e(-c))
		c = f(self.skew,random.random())
		index = int(len(sorted_list)*c)
		return sorted_list[index]
	def SelectAll(self,sorted_list,unique=True):
		#we can't have unique results if the input space is smaller
		#than the required output size
		if len(sorted_list)<= self.size: unique=False
		sl = sorted_list[:]
		result = []
		rt = []
		while True:
			if len(result)>=self.size: break
			if len(sl)==0: break
			choice = self.Select(sl)
			result.append(choice)
			if unique: sl.remove(choice)
		return result
class ShuffleQueue(object):
	PLUGIN_NAME = "Queue Selector"
	PLUGIN_DESC = "Randomly populates the queue"
	PLUGIN_VERSION = "0.0.1"
	def __init__(self):
		self.queue_size = 5
		self.skew = 5.0
		try:
			self.queue_size = config.getint("plugins","queue_selector_queue_size")
			self.skew = config.get("plugins","queue_selector_skew")
			self.skew = float(self.skew)
		except:
			pass
	def set_global_ratings(self,value):
		lib = library.library
		for s in lib.keys():
			song = lib[s]
			song[RATING] = 0.0
	def get_queue_count(self):
		return len(widgets.main.playlist.q)
	def clear_queue(self):
		widgets.main.playlist.q.clear()
	def create_selector(self,mid_point):
		def selector(song1,song2):
			rating1 = int(10.0*song1[RATING])
			rating2 = int(10.0*song2[RATING])
			diff1 = rating1 - mid_point
			diff2 = rating2 - mid_point
	def add_random_songs(self,count):
		if count< 1: return
		pending = []
		lib = library.library
		songs = lib.values()
		def cmp(s1,s2):
			if (s1[RATING]>s2[RATING]): return 1
			elif (s1[RATING]<s2[RATING]): return -1
			return 0
		songs.sort(cmp)
		s = Selector(count,self.skew)
		pending = s.SelectAll(songs)
		song_list = [AudioFile(x) for x in pending]
		widgets.main.playlist.enqueue(song_list)
	def add_random_songs_(self,count):
		if count < 1: return
		pending = []
		lib = library.library
		songs = lib.values()
		random.shuffle(songs)
		for song in songs:
			rating = song[RATING]
			if rating+random.random()>=1.0: 
				pending.append(AudioFile(song))
			if len(pending)>=count: break
		widgets.main.playlist.enqueue(pending)
	def plugin_on_song_ended(self,song,user_stopped):
		qc = self.get_queue_count()
		#print qc,"songs in queue" 
		self.add_random_songs(self.queue_size-qc)
	def plugin_song(self,song):
		pass
		#print song,"*"
		#print dir(song)
		#print song.get("~#length")
		#widgets.main.playlist.enqueue(song)
	def clear_queue_clicked(self,*args):
		self.clear_queue()
	def populate_queue_clicked(self,*args):
		self.add_random_songs(self.queue_size-self.get_queue_count())
	def queue_count_changed(self,spin,*args):
		self.queue_size = spin.get_value()
		config.set("plugins","queue_selector_queue_size",int(self.queue_size))
	def skew_changed(self,scale,*args):
		self.skew = scale.get_value()
		config.set("plugins","queue_selector_skew",self.skew)
	def refresh_queue_clicked(self,*args):
		self.clear_queue_clicked(*args)
		self.populate_queue_clicked(*args)
	def PluginPreferences(self,parent):
		vb = gtk.VBox()
		
		hb = gtk.HBox()
		hb.pack_start(gtk.Label("Number Of Songs In the Queue:"),expand=False)
		count = gtk.SpinButton(gtk.Adjustment(self.queue_size,1,100,1))
		count.connect("value-changed",self.queue_count_changed)
		hb.pack_start(count,expand=False)
		vb.pack_start(hb,expand=False)
		
		rbvb = gtk.VBox()
		hb = gtk.HBox()
		hb.pack_start(gtk.Label("Rating Bias"),expand=False)
		rbvb.pack_start(hb)
		hb = gtk.HBox()
		skew = gtk.HScale(gtk.Adjustment(self.skew,0.1,21.0,0.1,1.0,1.0))
		skew.connect("value-changed",self.skew_changed)
		hb.pack_start(skew)
		rbvb.pack_start(hb)

		vb.pack_start(rbvb,padding=20)

		clrbtn = gtk.Button("Clear Queue")
		clrbtn.connect("clicked",self.clear_queue_clicked)
		addbtn = gtk.Button("Add To Queue")
		addbtn.connect("clicked",self.populate_queue_clicked)
		rbtn = gtk.Button("Refresh Queue")
		rbtn.connect("clicked",self.refresh_queue_clicked)
		hb = gtk.HBox()
		hb.pack_start(clrbtn)
		hb.pack_end(addbtn)
		vb.pack_start(hb,expand=False)
		hb = gtk.HBox()
		hb.pack_start(rbtn,expand=True)
		vb.pack_start(hb)
		return vb

