# a plugin for pympd that scrapes data from audioscrobbler.com

from HTMLParser import HTMLParser
import urllib
import gtk, gtk.glade
import pygtk
import threading
import popen2

__name = 'Audioscrobbler lookup'
__version = '0.01'
__author = "Natan 'whatah' Zohar"
__blurb = 'This plugin will display similar artists according to data accumulated by last.fm'


NUM_ARTISTS = 11
PLUGIN_NAME = 'audioscrobbler'
class SimpleParser:
    def __init__(self, num_artists):
        self.num_artists = num_artists
        self.similarity = []
        self.artists = []
        self.count = 0

    def feed(self, line):
        if self.count == self.num_artists:
            return
        data = line.split(',')
        similarity = data[0].strip()
        artist = ','.join(data[2:]).strip()
        self.count += 1
        self.similarity.append(similarity)
        self.artists.append(artist)

    def clean(self):
        self.similarity = []
        self.artists = []
        self.count = 0

    def set_num_artists(self, num_artists):
        self.num_artists = num_artists


class Audioscrobbler:

    # called when we load the plugin. we get passed the mainWindow, plugin menu
    # item as well as a connection to mpd.
    def _init(self, data, get):
        self.xml, self.pluginMenu, self.pympd, self.base_dir, self.parser = data
        self.num_artists = NUM_ARTISTS
        self.browserCommand = "epiphany -n"
        self.readConfigParser()
        self.buildPluginMenu(self.pluginMenu)
        self.SParser = SimpleParser(self.num_artists)
        self.buildWindows()
        self.urlfile = urllib.URLopener()

    # plugin configure dialog.
    def _conf(self, hasDialog=None):
        if not hasDialog == None and hasDialog:
            return True
        self.spinner.set_value(self.num_artists)
        self.textbrowser.set_text(self.browserCommand)
        self.confDialog.present()
        return 
    
    # update plugin, data is of type mpdclient.Status
    def _spin(self, data, songChanged=False):
        pass

    # called on plugin unloaded
    def _unload(self):
        self.pluginMenuEntry.destroy()
        self.resultDialog.destroy()
        self.confDialog.destroy()
        self.saveConfigParser()
        return

    def readConfigParser(self):
        if self.parser.has_section(PLUGIN_NAME):
            self.num_artists = float(self.parser.get(PLUGIN_NAME, 'num_artists'))
            self.browserCommand = self.parser.get(PLUGIN_NAME, 'browser')

    def saveConfigParser(self):
        if not self.parser.has_section(PLUGIN_NAME):
            self.parser.add_section(PLUGIN_NAME)
            
        self.parser.set(PLUGIN_NAME, 'num_artists', str(self.num_artists))
        self.parser.set(PLUGIN_NAME, 'browser', self.browserCommand)


    # callback for find similar artists in menu
    def similarArtists(self, obj):
        song = self.pympd.getCurrentSong()
        thread = threading.Thread(target=self.OpenURL, args=[song.artist])
        thread.start()

    def OpenURL(self, artist):
        gtk.threads_enter()
        self.resultDialog.show_all()
        self.listStore.clear()
        self.listStore.append(['Retrieving Results...', ''])
        self.comboBox.set_active(0)
        gtk.threads_leave()
        file = self.urlfile.open("http://ws.audioscrobbler.com/1.0/artist/%s/similar.txt" % (artist.replace(' ', '+')))
        data = file.readlines()
        self.SParser.clean()
        for line in data:
            self.SParser.feed(line)
        self.urlfile.close()
        self.urlfile.cleanup()
        rows = zip(self.SParser.artists, self.SParser.similarity)
        gtk.threads_enter()
        self.listStore.clear()
        try:
            for n in range(0, len(rows)):
                self.listStore.append(["%s %s" % (rows[n][0], rows[n][1]), rows[n][0]])
            self.comboBox.set_active(0)
        except Exception, e:
            self.listStore.append(['Error Retrieving Results', ''])
        self.comboBox.set_model(self.listStore)
        gtk.threads_leave()

        
    # Init Functions
    def buildPluginMenu(self, pluginMenu):
        self.pluginMenuEntry = gtk.MenuItem('Audioscrobbler')
        pluginSubMenu = gtk.Menu()
        pluginSubMenu.set_title('Audioscrobbler')
        menuEntry = gtk.MenuItem('Show similar artists')
        menuEntry.connect('activate', self.similarArtists)
        pluginSubMenu.append(menuEntry)
        self.pluginMenuEntry.set_submenu(pluginSubMenu)
        self.pluginMenuEntry.show_all()
        pluginMenu.append(self.pluginMenuEntry)

    # Build the window we wanna display the information in. Somehow.
    def buildWindows(self):
        self.xml = gtk.glade.XML("%s/glade/audioscrobbler.glade"%self.base_dir)
        self.resultDialog = self.xml.get_widget("resultDialog")
        self.confDialog = self.xml.get_widget("confDialog")
        self.spinner = self.xml.get_widget("spinbutton1")
        self.texturl = self.xml.get_widget("entry1")
        self.textbrowser = self.xml.get_widget("entry2")
        self.lowlabel = self.xml.get_widget("label2")
        self.spinner.set_value(NUM_ARTISTS-1)
        self.treeView = self.xml.get_widget("treeview1")
        self.listStore = gtk.ListStore(str, str)
        self.label = self.xml.get_widget("label1")
        self.comboBox = self.xml.get_widget("combobox1")
        cellStr = gtk.CellRendererText()
        self.comboBox.pack_start(cellStr, True)
        self.comboBox.set_attributes(cellStr, text=0)
        self.comboBox.set_model(self.listStore)

        dic = {"on_dialog_closed"      : self.close_dialog,
               "on_dialog_ok"          : self.close_dialog,
               "on_ok_clicked"         : self.ok_clicked, 
               "on_cancel_clicked"     : self.cancel_clicked,
               "on_google_clicked"     : self.google_clicked,
               "on_scrobbler_clicked"  : self.scrobbler_clicked }
        self.xml.signal_autoconnect(dic)

    def ok_clicked(self, obj, data=None):
        self.num_artists = self.spinner.get_value()
        self.SParser.set_num_artists(self.num_artists)
        self.browserCommand = self.textbrowser.get_text()
        self.lowlabel.set_label("results from <u>Audioscrobbler.com</u>")
        self.confDialog.hide()

    def cancel_clicked(self, obj, data=None):
        self.confDialog.hide()

    def google_clicked(self, obj):
        model = self.comboBox.get_model()
        path = self.comboBox.get_active()
        iter = model.get_iter(path)
        value = model.get(iter, 1)[0].replace(' ', '%20')
        cmd = '%s \"http://www.google.com/search?&q=%s&btnG=Search\"' % (self.browserCommand, value)
        pop = popen2.Popen4(cmd)

    def scrobbler_clicked(self, obj):
        model = self.comboBox.get_model()
        path = self.comboBox.get_active()
        iter = model.get_iter(path)
        value = model.get(iter, 1)[0].replace(' ', '+')
        cmd = "%s http://www.last.fm/music/%s" % (self.browserCommand, value)
        pop = popen2.Popen4(cmd)
    
    # TODO: make more of these, one for destroy, 2 for close buttons.
    def close_dialog(self, obj, data=None):
        self.listStore.clear()
        self.resultDialog.hide()
        return True
        
    
