# -*- 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.

__maintainer__ = 'Philippe Normand <philippe@fluendo.com>'

from elisa.core import component
from elisa.core import media_uri
from elisa.base_components.media_provider import MediaProvider
from elisa.core.observers.dict import DictObservable

from elisa.core import common
from twisted.internet import defer, threads

from elisa.extern.coherence import et
import os
import urllib

plugin_registry = common.application.plugin_registry
ForeignApplicationMessage = plugin_registry.get_component_class('base:foreign_application_message')

DEFAULT_DB_PATH = os.path.join(os.path.expanduser('~'),
                               '.gnome2','rhythmbox','rhythmdb.xml')

class RbMedia(MediaProvider):
    default_config = {'db_path': DEFAULT_DB_PATH}
    config_doc = {'db_path': 'absolute path to rhythmdb.xml file'}

    def initialize(self):
        xml_db = self.config.get('db_path', DEFAULT_DB_PATH)
        if not os.path.exists(xml_db):
            msg = "Rhythmbox db not found at: %r" % xml_db
            raise component.InitializeFailure(self.name, msg)

        uri = "rb:///"
        action_type = ForeignApplicationMessage.ActionType.LOCATION_ADDED
        msg = ForeignApplicationMessage(action_type, "Rhythmbox",
                                             'rb', uri,
                                             media_types=['audio',],
                                             theme_icon='rhythmbox'
                                             )
        common.application.bus.send_message(msg)

        threads.deferToThread(self._load_db, xml_db)

    def _load_db(self, xml_db):
        self._tree = et.parse_xml(open(xml_db).read())
        self._entries = list(self._tree.findall(".//entry"))
        self._artists = {}

    def _get_artists(self):
        if self._artists == {}:
            for entry in self._entries:
                if entry.get('type') == 'song':
                    title = entry.find('title').text
                    artist_title = entry.find('artist').text
                    album_title = entry.find('album').text
                    location = urllib.unquote(entry.find('location').text)
                    mtime = entry.find('mtime').text

                    track_number = entry.find('track-number')
                    if track_number is not None:
                        track_number = int(track_number.text)
                    else:
                        track_number = 0

                    artist = self._artists.get(artist_title, {})
                    if album_title not in artist:
                        artist[album_title] = {track_number: (title, location,
                                                              mtime)}
                    else:
                        artist[album_title][track_number] = (title, location,
                                                             mtime)
                        
                    self._artists[artist_title] = artist
        return self._artists
        
    def supported_uri_schemes__get(self):
        return { 'rb': 0 }

    def _blocking_get_media_type(self, uri):
        mime_type = ''
        if uri.path == '/':
            file_type = 'directory'
        else:
            file_type = 'audio'
        return {'file_type': file_type, 'mime_type': mime_type}

    def _blocking_is_directory(self, uri):
        return uri.path == '/'
    
    def has_children_with_types(self, uri, media_types):
        return threads.deferToThread(self._blocking_has_children_with_types,
                                     uri, media_types)

    def _blocking_has_children_with_types(self, uri, media_types):
        has_children = False
        if 'directory' in media_types:
            if uri.get_param('track', None) is None:
                has_children = True
        return has_children
    
    def get_direct_children(self, uri, l):
        d = threads.deferToThread(self._blocking_get_direct_children, uri, l)
        return d

    def get_real_uri(self, uri):
        real_uri = media_uri.MediaUri(uri)
        artist = uri.get_param('artist', None)
        album = uri.get_param('album', None)
        track = uri.get_param('track', None)
        if None not in (artist, album, track):
            albums = self._get_artists().get(artist,{})
            track = int(track)
            if album in albums and track in albums[album]:
                real_uri = media_uri.MediaUri(albums[album][track][1])
        return real_uri
    
    def _blocking_get_direct_children(self, uri, children):
        self.debug("Retrieving children of: %s", uri)
        artists = self._get_artists()

        artist = uri.get_param('artist', None)
        album = uri.get_param('album', None)
        
        self.debug("URI artist and album are: %s - %s" % (artist,album))

        if artist != None and album != None:
            # process songs of given album of the artist
            for track_id, (track, location, mtime) in artists.get(artist).get(album).iteritems():
                metadata = DictObservable()
                child_uri = media_uri.MediaUri('rb:///track')
                child_uri.set_params({'artist': artist, 'album': album,
                                      'track': track_id})
                child_uri.label = track
                metadata['artist'] = artist
                metadata['album'] = album
                metadata['song'] = track
                metadata['file_type'] = 'audio'
                metadata['fs_mtime'] = mtime
                self.debug("Appendind %r with metadata %s" % (child_uri,
                                                              metadata))
                children.append((child_uri, metadata))
                
        elif artist != None and album == None:
            # list albums of given artist
            for album_name, album in artists.get(artist,{}).iteritems():
                metadata = DictObservable()
                child_uri = media_uri.MediaUri(uri.parent)
                metadata['artist'] = artist
                metadata['album'] = album_name
                child_uri.set_params({'artist' : artist,
                                      'album' : album_name})
                child_uri.label = album_name
                self.debug("Appendind %r with metadata %s" % (child_uri,
                                                              metadata))
                children.append((child_uri, metadata))
                
        elif uri.get_param('list_artists'):
            # list artists
            for artist in artists.keys():
                metadata = DictObservable()
                child_uri = media_uri.MediaUri(uri.parent)
                child_uri.set_params({'artist': artist})
                child_uri.label = artist
                metadata['artist'] = artist
                self.debug("Appendind %r with metadata %s" % (child_uri,
                                                              metadata))
                children.append((child_uri,metadata))
        elif uri.get_param('list_albums'):
            # list albums
            for artist, albums in artists.iteritems():
                for album_name, album in albums.iteritems():
                    metadata = DictObservable()
                    child_uri = media_uri.MediaUri(uri.parent)
                    metadata['artist'] = artist
                    metadata['album'] = album_name
                    child_uri.set_params({'artist' : artist,
                                          'album' : album_name})
                    child_uri.label = album_name
                    self.debug("Appendind %r with metadata %s" % (child_uri,
                                                                  metadata))
                    children.append((child_uri, metadata))                
        else:
            # build main menu
            children = self._build_main_menu(children)
            
        self.debug("Retrieved children: %r", children)
        return children

    def _build_main_menu(self, children):

        artists = media_uri.MediaUri('rb:///?list_artists=1')
        artists.label = "By artist"
        children.append((artists,{}))

        albums = media_uri.MediaUri('rb:///?list_albums=1')
        albums.label = "By album"
        children.append((albums,{}))

        return children

##     def _blocking_next_location(self, from_uri, root=None):
##         next_uri = None
