# A cover viewer plugin

import copy
import xml.parsers.expat
import urllib
import gtk, gtk.glade
import pygtk
import threading
import os
import ConfigParser

__name = 'Embedded Art'
__version = '0.01'
__author = "Natan 'whatah' Zohar"
__blurb = 'Embedded Art will automatically find and download album art as well as display it in the lower left hand corner of the main window.'
COVER_PATH = os.path.expanduser("~/.covers/")
DB_FILE = os.path.expanduser("~/.covers/covers.db")

# Remove everything inside parantheses or brackets within a string
def remove_parantheses(string):
    open = False
    ret = ''
    for char in string:
        if char == '(' or char == '[' or char == '{':
            open = True
        if not open:
            ret += char
        if char == ')' or char == ']' or char == '}':
            open = False
    return ret

class Result:
    asin = ''
    productname = ''
    catalog = ''
    artists = []
    releasedate = ''
    manafacturer = ''
    imageurlsmall = ''
    imageurlmedium = ''
    imageurllarge = ''

class Parser:
    results = []
    result = Result()
    attr = ''
    def start_element(self, name, attrs):
        pass
    def end_element(self, name):
        if name.lower() == 'details':
            result_open = False
            self.results.append(copy.deepcopy(self.result))
        setattr(self.result, name.lower(), self.attr)
    def char_data(self, data):
        self.attr = data

class Embeddedart:

    # 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):
        if not os.path.exists(os.path.expanduser(COVER_PATH)):
            print 'Creating coverart directory'
            os.mkdir(COVER_PATH)
        self.xml, self.pluginMenu, self.pympd, self.base_dir, parser = data
        self.parent = self.xml.get_widget("hbox2")
        self.readConfigParser(DB_FILE)
#        self.buildPluginMenu(self.pluginMenu)
        self.buildInfoWindow()
        self.urlfile = urllib.URLopener()
        self.r = Parser()
        self.CVurl = "http://xml.amazon.com/onca/xml3?t=webservices-20&dev-t=1SR4P88NA1BQ5RZVWK02"
        self.displayedImage = None
        self.browseCovers(None)

    # plugin configure dialog.
    def _conf(self, hasDialog=None):
        return False

    # update plugin, data is of type mpdclient.Status
    def _spin(self, data, songChanged=False):
        if songChanged:
            self.browseCovers(None)
        pass

    # called on plugin unloaded
    def _unload(self):
        self.saveConfigParser(DB_FILE)
        self.parent.remove(self.image)
#        self.pluginMenuEntry.destroy()
        return

    def readConfigParser(self, filename):
        self.configParser = ConfigParser.ConfigParser()
        self.configParser.read(filename)

    def saveConfigParser(self, filename):
        self.configParser.write(open(filename, 'w'))

    # callback for find similar artists in menu
    def browseCovers(self, obj):
        song = self.pympd.getCurrentSong()
        if not song == False:
            if song.artist.strip() == '' or song.album.strip() == '':
                self.noImage()
                return
            search_term = song.artist + '-' + song.album
            image_path = "%s%s.jpg" % (COVER_PATH, search_term)

            if self.configParser.has_section(song.artist) and self.configParser.has_option(song.artist, song.album):
                path = self.configParser.get(song.artist, song.album).strip('"')
                if os.path.exists(path):
                    image_path = path
                else:
                    self.noImage()

            if os.path.exists(image_path):
                thread = threading.Thread(target=self.dispImage, args=[None, image_path])
                if not self.configParser.has_section(song.artist):
                    self.configParser.add_section(song.artist)
                self.configParser.set(song.artist, song.album, '"%s"'%image_path)
                thread.start()
            else:
                thread =threading.Thread(target=self.OpenURL, args=[song.artist, song.album])
                thread.start()


    def OpenURL(self, artist, album):
        search_term = artist + ' - ' + album
        search_term = remove_parantheses(search_term)
        file = self.urlfile.open("%s&KeywordSearch=%s&mode=music&type=lite&page=1&f=xml" % (self.CVurl, search_term.replace(' ', '%20')))
        lines = file.readlines()
        data = ''
        for line in lines:
            data += line
        #make a new parser for ourselves
        self.newParser()
        self.parser.Parse(data)
        file.close()
        self.urlfile.close()

        if len(self.r.results) > 0:
            self.dispImage(self.r.results[0].imageurllarge, None, artist, album)
        else:
            self.noImage()

    def dispImage(self, imageurl=None, imagepath=None, artist=None, album=None):
        if not artist == None and not album == None:
            search_term = artist + '-' + album
        if not imageurl == None:
            image_name = imageurl[imageurl.rfind('/')+1:]
            image_path = "%s%s.jpg" % (COVER_PATH, search_term)
            if not self.configParser.has_section(artist):
                self.configParser.add_section(artist)
            self.configParser.set(artist, album, '"%s"'%image_path) #Cache the cover into our database.
        if not imagepath == None:
            image_path = imagepath
        if self.displayedImage == image_path:
            return
        if os.path.exists(image_path):
            pass
        else:
            self.urlfile.retrieve(imageurl, image_path)[0]
        gtk.gdk.threads_enter()
        self.image.set_from_file(None)
        pixbuf = gtk.gdk.pixbuf_new_from_file(image_path)
        pixbuf = pixbuf.scale_simple(60, 60, gtk.gdk.INTERP_BILINEAR)
        pixbuf2 = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 62, 62)
        pixbuf2.fill(0x00000001)
        pixbuf.copy_area(0,0,60,60,pixbuf2,1,1)
        self.image.set_from_pixbuf(pixbuf2)
        self.image.show_all()
        gtk.gdk.threads_leave()
        self.displayedImage = image_path

    def noImage(self):
        gtk.gdk.threads_enter()
#        self.image.hide()
        pixbuf = gtk.gdk.pixbuf_new_from_file("%s/glade/pympd.svg"%self.base_dir)
        pixbuf = pixbuf.scale_simple(60, 60, gtk.gdk.INTERP_BILINEAR)
        self.image.set_from_pixbuf(pixbuf)
        self.image.show()
        gtk.gdk.threads_leave()


    def newParser(self):
        self.r.results = []
        self.parser = xml.parsers.expat.ParserCreate()
        self.parser.StartElementHandler = self.r.start_element
        self.parser.EndElementHandler = self.r.end_element
        self.parser.CharacterDataHandler = self.r.char_data


#    # Init Functions
#    def buildPluginMenu(self, pluginMenu):
#        self.pluginMenuEntry = gtk.MenuItem('Cover Viewer')
#        pluginSubMenu = gtk.Menu()
#        pluginSubMenu.set_title('Coverviewer')
#        menuEntry = gtk.MenuItem('Show Album Covers')
#        menuEntry.connect('activate', self.browseCovers)
#        pluginSubMenu.append(menuEntry)
#        self.pluginMenuEntry.set_submenu(pluginSubMenu)
#        self.pluginMenuEntry.show_all()
#        pluginMenu.append(self.pluginMenuEntry)
#
    def buildInfoWindow(self):
        self.image = gtk.Image()
        self.parent.pack_start(self.image, expand=False, fill=False, padding=3)
        self.parent.reorder_child(self.image, 0)
