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

"""
Shoutcast Media Provider
"""


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

from elisa.base_components.media_provider import MediaProvider
from elisa.core.media_uri import MediaUri
from elisa.core import common

from elisa.extern.coherence.et import parse_xml

from twisted.internet import defer, threads

import urllib2, re

plugin_registry = common.application.plugin_registry
InternetLocationMessage = plugin_registry.get_component_class('base:internet_location_message')

# FIXME: use a non-blocking library to retrieve web pages (such as twisted.web
# or even simpler Elisa's media_manager)

class ShoutcastMedia(MediaProvider):
    """
    This class implements support for the shoutcast servers and playlist 
    """

    shout_uri = "http://www.shoutcast.com/sbin/newxml.phtml"
    pl_getter = re.compile('File.=(.*?)\n')

    intresting_genres = set([ 'Alternativ', "Classical", "Comedy", "Country",
                              "Dance", "Funk", "Jazz", "Metal", "Mixed",
                              "Pop", "Rap", "RnB", "Rock", "Talk", "Techno",
                              "80s", "70s", "World"])
    def initialize(self):
        self._all = []
        uri = "shoutcast:///"
        action_type = InternetLocationMessage.ActionType.LOCATION_ADDED
        msg = InternetLocationMessage(action_type, "Shoutcast",
                                            'shoutcast',
                                            uri,
                                            media_types=['audio',],
                                            theme_icon='shoutcast'
                                           )
        common.application.bus.send_message(msg)
        
    def _read_url(self, url):
        fread = urllib2.urlopen(url)
        return fread.read()
 
    def supported_uri_schemes__get(self):
        return { 'shoutcast': 0 }

    def scannable_uri_schemes__get(self):
        return []

    def _blocking_get_media_type(self, uri):
        if self._blocking_is_directory(uri):
            return {'file_type' : 'directory',
                    'mime_type' : 'mime_type'}

        return {'file_type' : 'audio', 'mime_type' : 'mp3'}

    def _blocking_is_directory(self, uri):
        if uri.host == 'PLAY':
            return False
        return True

    def get_media_type(self, uri):
        d = threads.deferToThread(self._blocking_get_media_type,
                                  uri)
        return d


    def has_children_with_types(self, uri, media_types):
        d = threads.deferToThread(self._blocking_has_children_with_types,
                                  uri, media_types)
        return d

    def _blocking_has_children_with_types(self, uri, media_types):
        if self._blocking_is_directory(uri):
            if 'audio' in media_types:
                return True
        return False

    def _blocking_get_direct_children(self, uri, list_of_children):

        if self._blocking_is_directory(uri):
            if uri.host == "ALL":
                for sub_uri in self._all:
                    list_of_children.append( (sub_uri, {}) )
            elif uri.path == '/':
                if len(self._all) == 0:
                    xml = parse_xml(self._read_url(self.shout_uri))
    
                    for elem in xml.findall('genre'):
                        name = elem.get('name')
                        uri = MediaUri('shoutcast:///%s' % name)
                        uri.label = name
                        self._all.append(uri)
                        if name in self.intresting_genres:
                            list_of_children.append( (uri, {}) )
                else:
                    for uri in self._all:
                        if uri.label in self.intresting_genres:
                            list_of_children.append( (uri, {}) )

                all_uri = MediaUri('shoutcast://ALL/')
                # FIXME: hardcoded is bad!
                all_uri.label = "All Genres"
                list_of_children.append( (all_uri, {}))
            else:
                # We have a genre
                genre = uri.path[1:]
                path = '%s?genre=%s' %(self.shout_uri, genre)
                xml = parse_xml(self._read_url(path))

                tune_in = xml.find('tunein')
                base = tune_in.get('base')

                for elem in xml.findall('station'):
                   name = elem.get('name')
                   id = elem.get('id')
                   uri = MediaUri('shoutcast://PLAY%s' % base)
                   uri.set_param('id', id)
                   uri.label = name

                   list_of_children.append( (uri, {}) )
                   if len(list_of_children) >= 20:
                       break

        return list_of_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):
        if self._blocking_is_directory(uri):
            return uri

        path = "http://www.shoutcast.com%s?id=%s" % (uri.path,
                                                     uri.get_param('id'))
        data = self._read_url(path)
        res = self.pl_getter.search(data)
        if res:
            link = res.groups()[0]
            new_uri = MediaUri(link)
            return new_uri
        return uri
