# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

"""
Amazon Cover Loading
"""


__maintainer__ = 'Benjamin Kampmann <benjamin@fluendo.com>'

from elisa.extern.coherence.covers_by_amazon import CoverGetter, aws_server

from elisa.base_components.metadata_provider import MetadataProvider
from elisa.core.media_uri import MediaUri, quote

from elisa.core.component import InitializeFailure

import time, os
import pickle
from twisted.internet import threads, reactor

#
#
#
# IF YOU WANT TO USE THIS FILE OUTSIDE OF ELISA, YOU'LL HAVE TO REPLACE THIS
# KEY WITH YOUR ONE!!! THIS ONE IS FOR THE USE OF ELISA ONLY!
#
#
#
aws_key = '0BRN2M3KEQFQ34YKARG2'

class AmazonCovers(MetadataProvider):

    config_doc = {'locale': 'set your locale amazon here, could be any '
                            'of de,jp,ca,uk,fr'}

    # FIXME: Change this to work with the local homedir
    default_config = {'locale': ''}

    def __init__(self):
        MetadataProvider.__init__(self)

        # A dictionary containing files which point to their timestamps
        self._expire_dict = {}

        self._cache = os.path.join(os.path.expanduser("~"), ".elisa",
                                   "amazon_cache")
        self._cache_filename = os.path.join(self._cache, "cache.txt")
        
        self._already_asked = []

    def initialize(self):
        # setting up the locale
        locale = self.config.get('locale' , '')
        self._locale = None

        if locale != '':
            if locale in aws_server.keys():
                self._locale = locale
            else:
                self.warning("Locale '%s' not supported by amazon_covers",
                             locale)

        if not os.path.exists(self._cache):
            try:
                os.makedirs(self._cache)
            except OSError, e:
                self.warning("Could not create the amazon caching directory" \
                             " '%s': '%s'. This Media Provider will be" \
                             " deactivated" % (self._cache, e))
                raise InitializeFailure('amazon_metadata', e)

        if os.path.isfile(self._cache_filename):
            fd = open(self._cache_filename)
            try:
                self._expire_dict = pickle.load(fd)
            except EOFError:
                # Sometimes pickle loading fails, so we drop it
                self.expirce_dict = {}
            fd.close()
            
        reactor.callLater(2, self.delete_expired)

    def clean(self):
        MetadataProvider.clean(self)
        fd = open(self._cache_filename, 'w')
        pickle.dump(self._expire_dict, fd)
        fd.close()

    def get_rank(self):
        return 200

    def able_to_handle(self, metadata):
        if metadata.get('album', None) == None:
            return False

        if metadata.get('cover', None) != None:
            if metadata.get('default_image' , '') != None:
                return False

        return True

    def delete_expired(self):
        for file_name, atime in self._expire_dict.items():
            if atime <= time.time() + 86400:
                os.remove(file_name)
                del self._expire_dict[file_name]
                if file_name in self._already_asked:
                    # FIXME: where's that remove() method defined?
                    self.remove(file_name)

        # Call me again tomorrow
        reactor.callLater(86400, self.delete_expired) 

    def get_metadata(self, metadata, low_priority=False):
        d = threads.deferToThread(self._get_cover, metadata)
        return d

    def _get_album (self, metadata):
        album = metadata['album'].lower().strip()
        # FIXME: what about all other special characters??
        album = album.replace(unicode(u'ä'),unicode('ae'))
        album = album.replace(unicode(u'ö'),unicode('oe'))
        album = album.replace(unicode(u'ü'),unicode('ue'))
        album = album.replace(unicode(u'ß'),unicode('ss'))
        return album

    def _get_artist (self, metadata):
        if metadata.get('artist', None) == None:
            return None
        artist = metadata['artist'].lower().strip()
        # FIXME: what about all other special characters??
        artist = artist.replace(unicode(u'ä'),unicode('ae'))
        artist = artist.replace(unicode(u'ö'),unicode('oe'))
        artist = artist.replace(unicode(u'ü'),unicode('ue'))
        artist = artist.replace(unicode(u'ß'),unicode('ss'))
        return artist


    def _get_cover(self, metadata):

        # we'll do it for the remote look up. So why don't do it here also?
        album = self._get_album(metadata)
        artist = self._get_artist(metadata)
        if album == None or album == '':
            return metadata

        path= unicode(os.path.join(self._cache, "%s.png" % album))

        self.debug("searching for file: '%s'" % path)

        if os.path.exists(path):
            self.debug("Found file %s" % path)
            return self._set_cover(metadata, path)


        if path in self._already_asked:
            return metadata

        if artist:
            self._doing_album_and_artist_lookup(path, metadata, self._locale)
            return metadata

        self._doing_album_lookup(path, metadata, self._locale)
        return metadata


    def _got_new_image(self, a, b, c):
        path = a
        metadata = c
        # this image will expire 28 days later, like in the movie, dude
        self._expire_dict[path] = time.time() + 2419200
        self.debug("image found: %s for %s"  % (path, metadata))
        self._set_cover(metadata, path)

    def _image_not_found(self, path, metadata, album=0, locale=None):
        if album and not locale:
            self.debug("Sorry, no amazon images found for %s" % metadata)
            return

        if locale:
            if album:
                self.debug("No images found for locale '%s', trying default",
                           locale)
                self._doing_album_lookup(path, metadata, locale=None)
                return
            self.debug("No artist and album found for locale '%s'. "\
                       "trying to look up for default locale")

            self._doing_album_and_artist_lookup(path, metadata, locale=None)

        else:
            if not album:
                self.debug("No artist-album combination found performing "\
                           "a lookup of covers only")
                self._doing_album_lookup(path, metadata, locale=self._locale)
                return
            self.debug("Sorry nothing found for '%s'" % metadata)


    def _doing_album_and_artist_lookup(self, path, metadata, locale=None):
        self._already_asked.append(path)
        self.debug("Doing lookup for %s" % path)
        g = CoverGetter(path, aws_key,
                        callback=(self._got_new_image, (path, metadata)),
                        not_found_callback=(self._image_not_found, (path,
                                                                    metadata,
                                                                    0, locale)),
                        artist=metadata.get('artist'),
                        title=metadata.get('album'))

    def _doing_album_lookup(self, path, metadata, locale):
        self.debug("Doing lookup for %s" % path)
        self._already_asked.append(path)
        g = CoverGetter(path, aws_key,
                        locale=locale,
                        callback=(self._got_new_image, (path, metadata)),
                        artist=None,
                        not_found_callback=(self._image_not_found,(path,
                                                                   metadata,1,
                                                                   locale)),
                        title=self._get_album(metadata))

    def _set_cover(self, metadata, cover):
        cover_path = MediaUri("file://%s" % cover)
        if metadata.get('cover', None) == None:
            metadata['cover'] = cover_path
            
        # Set globally image if not set yet:
        if metadata.get('default_image', '') == None:
            metadata['default_image'] = cover_path

        self.debug("returning this dict: %s" % metadata)
        return metadata



if __name__ == "__main__":

    c = AmazonCovers()
    c.config = {'cache' : '/tmp/amazon'}
    c.initialize()

    def start_test():

        def print_dict(mdict):
            print 'got this dict:', mdict

        def end_up():
            c.clean()
            reactor.stop()

        def power_asking():
            ask_it({u'artist': u'coldplay',
                    u'album' : u'Parachutes'})
            ask_it({u'artist': u'gorillaz',
                    u'album' : u'gorillaz'})
            ask_it({u'artist': u'gorillaz',
                    u'album' : u'demon days'})
            ask_it({u'artist': u'The Good, the Bad & the Queen',
                    u'album' : u'The Good, the Bad & the Queen'})
            ask_it({u'artist': u'toten hosen',
                    u'album' : u'Unplugged Im Wiener Burgtheater'})

            ask_it({u'artist': u'gorillaz', # Wrong Artist
                    u'album' : u'demon days live (At Manchester)'})

            ask_it({u'artist': u'The Good, the Bad & the Queen',
                    u'album' :'not_existing'}) # Wrong Album

                # Is the same (should return one file)
            ask_it({u'artist': u'toten hosen',
                    u'album' : u'unsterblich'})
            ask_it({u'artist': u'Toten Hosen',
                    u'album' : u'Unsterblich'})


                # Test for lstrip: bot are the same
            ask_it({u'artist': u'  coldplay  ',
                    u'album' : u'  x&y  '})
            ask_it({u'artist': u' coldplay ',
                    u'album' : u' x&y  '})


        def ask_it(dict):
            df = c.get_metadata(dict)
            df.addCallback(print_dict)

        power_asking()
        reactor.callLater(15,power_asking)
        reactor.callLater(30, end_up)


    reactor.callWhenRunning(start_test)

    reactor.run()
